更效率、更优雅 | 阿里巴巴开发者工具不完全盘点

从人工到自动化,从重复到创新,技术演进的历程中,伴随着开发者工具类产品的发展。阿里巴巴将自身在各类业务场景下的技术积淀,通过开源、云上实现或工具等形式对外开放,本文将精选了一些阿里巴巴的开发者工具,希望能帮助开发者们提高开发效率、更优雅的写代码。由于开发者涉及的技术领域众多,笔者仅从自己熟悉的领域,以后端开发者的视角盘点平时可能有得到的工具。每个工具按照以下几点进行介绍:工具名称和简介使用场景使用教程获取方式一、Java 线上诊断工具 ArthasArthas 阿里巴巴2018年9月开源的一款Java线上诊断工具。工具的使用场景:这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!是否有一个全局视角来查看系统的运行状况?有什么办法可以监控到JVM的实时运行状态?Arthas支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。使用教程:基础教程:https://alibaba.github.io/arthas/arthas-tutorials?language=cn&id=arthas-basics进阶教程:https://alibaba.github.io/arthas/arthas-tutorials?language=cn&id=arthas-advanced获取方式:(免费)开源地址:https://github.com/alibaba/arthas二、IDE 插件 Cloud ToolkitCloud Toolkit 是一款 IDE 插件,可以帮助开发者更高效地开发、测试、诊断并部署应用。通过 Cloud Toolkit,开发者能够方便地将本地应用一键部署到任意机器(本地或云端),并内置 Arthas 诊断、高效执行终端命令和 SQL 等。工具的使用场景:每次修改完代码后,是否正在经历反复地打包?在 Maven 、Git 以及其他运维脚本和工具的之间频繁切换?采用 SCP 工具上传?使用XShell或SecureCRT登陆服务器?替换部署包?重启?文件上传到服务器指定目录,在各种 FTP、SCP 工具之间频繁切换 ?使用教程:IntelliJ IDEA 版:https://help.aliyun.com/document_detail/98762.htmlEclipse 版:https://help.aliyun.com/document_detail/29970.htmlPyCharm 版:https://help.aliyun.com/document_detail/112740.htmlMaven 版:https://help.aliyun.com/document_detail/108682.html获取方式:(免费)工具地址:https://www.aliyun.com/product/cloudtoolkit三、混沌实验注入工具 ChaosBladeChaosBlade 是一款遵循混沌工程实验原理,提供丰富故障场景实现,帮助分布式系统提升容错性和可恢复性的混沌工程工具,可实现底层故障的注入,提供了延迟、异常、返回特定值、修改参数值、重复调用和try-catch 块异常等异常场景。工具的使用场景:微服务的容错能力不易衡量?容器编排配置是否合理无法验证?PaaS 层健壮性的测试工作无从入手?使用教程:https://github.com/chaosblade-io/chaosblade/wiki/新手指南获取方式:(免费)开源地址:https://github.com/chaosblade-io/chaosblade/wiki/新手指南四、Java 代码规约扫描插件该插件用于检测 Java 代码中存在的不规范的位置,并给予提示。规约插件是采用kotlin语言开发。使用教程:IDEA插件使用文档:https://github.com/alibaba/p3c/wiki/IDEA插件使用文档Eclipse插件使用文档:https://github.com/alibaba/p3c/wiki/Eclipse插件使用文档获取方式:(免费)开源地址:https://github.com/alibaba/p3c五、应用实时监控工具 ARMSARMS 是一款 APM 类的监控工具,提供前端、应用、自定义监控 3 类监控选项,可快速构建实时的应用性能和业务监控能力。工具的使用场景:晚上10点收到37条报警信息,你却无从下手?当我们发现问题的时候,客户/业务方已经发起投诉?每个月花几十万买服务器,却无法保障用户体验?使用教程:前端监控接入:https://help.aliyun.com/document_detail/106086.html应用监控接入:https://help.aliyun.com/document_detail/63796.html自定义监控:https://help.aliyun.com/document_detail/47474.html获取方式:(收费)工具地址:https://www.aliyun.com/product/arms六、静态开源站点搭建工具 DocsiteDocsite 一款集官网、文档、博客和社区为一体的静态开源站点的解决方案,具有简单易上手、上手不撒手的特质,同时支持 react 和静态渲染、PC端和移动端、支持中英文国际化、SEO、markdown文档、全局站点搜索、站点风格自定义、页面自定义等功能。使用教程:https://docsite.js.org/zh-cn/docs/installation.html获取方式:(免费)项目地址:https://github.com/txd-team/docsite七、Android 平台上的秒级编译方案 FreelineFreeline 可以充分利用缓存文件,在几秒钟内迅速地对代码的改动进行编译并部署到设备上,有效地减少了日常开发中的大量重新编译与安装的耗时。Freeline 最快捷的使用方法就是直接安装 Android Studio 插件。使用教程:https://github.com/alibaba/freeline/blob/master/README-zh.md获取方式:(免费)项目地址:https://github.com/alibaba/freeline八、性能测试工具 PTSPTS 可以模拟大量用户访问业务的场景,任务随时发起,免去搭建和维护成本,支持 JMeter 脚本转化为 PTS 压测,同样支持原生 JMeter 引擎进行压测。使用教程:https://help.aliyun.com/document_detail/70290.html获取方式:(收费)工具地址:https://www.aliyun.com/product/pts九、云效开发者工具KTKT 可以简化在 Kubernetes 下进行联调测试的复杂度,提高基于Kubernetes的研发效率。使用教程:https://yq.aliyun.com/articles/690519获取方式:(免费)工具地址:https://yq.aliyun.com/download/3393十、架构可视化工具 AHASAHAS 为 K8s 等容器环境提供了架构可视化的功能,同时,具有故障注入式高可用能力评测和一键流控降级等功能,可以快速低成本的提升应用可用性。工具的使用场景:服务化改造过程中,想精确的了解资源实例的构成和交互情况,实现架构的可视化?想引入真实的故障场景和演练模型?低门槛获得流控、降级功能?使用教程:https://help.aliyun.com/document_detail/90323.html获取方式:(免费)工具地址:https://www.aliyun.com/product/ahas本文作者:中间件小哥阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

April 11, 2019 · 1 min · jiezi

在github上,如何添加ssh keys(ssh公钥)

注:下面操作在linux和windows中都适用1. 打开git bash2. 输入 ssh-keygen -t rsa -C ‘your_email@example.com’(注:your_email@example.com是你的邮箱) 之后会跳出不少信息,全部按enter就可以)3. 找到你的id_rsa.pub文件,打开复制里面的全部内容id_rsa.pub文件的存储位置,上面会有提示,像我的id_rsa.pub文件的路径在/home/jixn/.ssh/id_rsa.pub4. 进入github中,打开个人设置,点击SSH and GPG keys选项5. 点击新增公钥,将之前复制的内容全部粘贴到公钥内容里,公钥名称会自己生成,也可以自己修改,点击添加6. 再次进入git bash,进行命令行测试,首次建立链接会要求信任主机。输入命令 ssh -T git@github.com提示成功则表示已经正确的完成了添加 shh keys的全部操作!!!

April 10, 2019 · 1 min · jiezi

Zilliqa进度更新第31期—引导阶段结束

2019年4月2日Saiba Kataruka 发布于Zilliqa博客大家好!和往常一样, Zilliqa 又有很多新的发展!您可能已经在我们的 Twitter 和社区频道的公告中了解到,最重要的消息是,我们的引导阶段正式结束。借此机会,我们要感谢不断增长的社区在这段时间的支持:真的非常感谢大家!在这一阶段,我们遇到了一些问题,对于一个新的大规模去中心化网络来说,这都是预料中事,我们采取措施一一解决,提高了 Zilliqa 平台的整体质量。引导阶段结束之后会发生什么?●人们已经开始使用 Zilliqa 网络来处理交易●矿工可以开始将代币转入其他账户●社区开发者可以开始尝试支付服务为了确保代币交换成功(这项工作计划于 4 月底开始),以及更好地支持交易所及钱包,我们已开放 Zilliqa 网络,只容许支付交易,也就是说Zilliqa网络的智能合约功能将暂时关闭。代币交换完成之后,我们将通过一次网络升级在主网上启用智能合约功能,具体日期会在2019 年 5 月下旬公布。Zilliqa 的专家登上福布斯要告诉大家一个好消息,我们社区中的两名成员在 2019 年福布斯「亚洲 30 位 30 岁以下精英榜」中获得提名。我们的联合创始人兼 CTO 贾瑶琪因其在科技领域的卓越成就和领导能力而受到认可。他不仅是一位领导者,而且是一位学者。他拥有新加坡国立大学的博士学位,他的研究得到了谷歌和苹果公司的认可。他发表过多篇顶级安全会议论文,并获得 W2SP 和 ICECCS 最佳论文奖。点击这里(地址:https://www.forbes.com/profil…)了解更多内容。源移动娱乐平台 BOLT 的联合创始人郭蕙萁 (Christel Quek) 也榜上有名(她同时是Zilliqa 值得信赖的顾问之一)。Christel 确实启发了所有人,尤其是对于深耕于科技和数字经济中的女性和千禧一代。与传立媒体的商业广告宣传活动此外还有其他令人雀跃的消息。在过去的两个月,我们已经与传立媒体(Mindshare)完成了我们的第一个区块链试点。这次的区块链试点是一次基于程序化广告网络,面向东南亚用户的商业广告宣传活动。质子计划(Project Proton)的目的是使广告网络透明化,杜绝欺诈造成的广告支出浪费。该计划利用区块链打造一个基于可验证浏览量的自动化结算方案,该计划可以帮助广告商创建一个可信的生态系统,在这个生态系统中,他们只需为那些被认定是可观看、品牌安全、没有欺诈的广告浏览量付费。我们的目标是整理项目成果并在接下来的几个月呈现给大家。我们会不断向社区更新进展。伦敦国王学院区块链 A-Z 研讨会:第一场取得成功上周,我们的市场主管 Kataruka Saiba 与伦敦国王学院区块链协会合作成功地启动了区块链 A-Z 研讨会。该系列活动的第一场在伦敦国王学院斯特兰德校区标志性的布什大楼举行。该场活动聚焦于“区块链入门”,吸引了来自 70 多位参与者,他们中既有学生,也有经验丰富的专业人士,都来自各个不同领域。看到这样的互动和他们对区块链感兴趣非常令人兴奋,而且这只会继续增长!Saiba 现在准备发布研讨会的三个后续模块,包括区块链的用例、启动区块链上的应用程序和一个演示日活动。我们将不断与您分享这一精彩计划的最新进展。欢迎所有感兴趣的朋友在 Eventbrite 上注册,也鼓励申请 Zilliqa 的生态构建资助计划,该计划的奖金池为 500 万美元。下面是研讨会上的的精彩照片。同往常一样,如您想要了解Zilliqa的更多信息或与我们讨论项目技术,请随时通过以下官方渠道与我们联系:Discourse论坛:https://forum.zilliqa.com/电报群:https://t.me/zilliqachatSlack:https://invite.zilliqa.com推特:https://twitter.com/zilliqaReddit: https://www.reddit.com/r/zilliqa/Github:https://github.com/Zilliqa/zilliqaGitter:https://gitter.im/Zilliqa/ecogrant(开发相关专用频道,包括「生态构建资助计划」)已举办的活动在最近举行的 Money 20/20 Asia论坛上,Max Kantelia 与业界专家们,包括Primitive Ventures 联合创始人万卉 Dovey Wan,NEM 基金会联合创始人 Jeff McDonald,以及 Ripple 产品高级副总裁 Asheesh Birla一道,讨论了私有区块链和公有链高吞吐量的重要性。本周早些时候,Max Kantelia 还在伦敦区块链周上谈到了区块链技术的未来,以及它针对企业和消费者的应用。即将举行的活动如果您想在我们即将举行的活动中与我们联系,请随时与我们沟通。4月·巴黎区块链周|4 月 13–19 日|法国巴黎·FiNext 大会|4月 25–26 日|新加坡5月·Consensus 2019|5 月 13–15 日|纽约·2019 年 Echelon 亚洲峰会|5 月 23–24 日|新加坡技术进展Zilliqa主网的引导阶段(bootstrap phase)已经结束,核心技术团队在此阶段的最后两周进行了大量艰苦的工作,将主网升级到最新版本 4.4.0 及其后续的热修复版本 4.4.1。除了我们在每次升级中引入的安全性和功能修复之外,4.4.0 版本的主要改进还围绕着存储、挖矿和可用性。在存储方面,我们在测试期间注意到,默克尔树(Merkle Tree) 数据结构可以显著增长,因为每个帐户的每次更新都作为一个新条目添加到状态树中。此外,每个周期终结后,我们的协议没有必要为这些相同的帐户保留旧的条目。解决这个存储问题的方法是在经过几个目录服务 DS周期后定期刷新状态树(即重新创建帐户状态),代价是牺牲一些处理效率。由于交易(和帐户更新)只在引导阶段结束之后处理,因此在该阶段结束之前引入此修复显然很重要。版本4.4.0 还引入了新的增量数据库特性。这个特性允许加入网络的新节点首先从 AWS 存储中下载旧块。然后,其余的同步过程将通过查找节点(lookup notes)完成。这就减少了从新节点接收大量历史数据的过多请求的查找。对于挖矿代码的更新,最值得注意的是引入了一种新的难度调整算法。矿工可能在引导阶段观察到,网络会周期性地丢失或重新获得整个分片。每次难度值增加 1,实际难度就会增加 1 倍,这就要求算力增加 1 倍。之前节点一直能够满足算力需求,直到最近,丢失分片开始有规律发生。为了解决这个问题,我们集成了一个社区贡献者(deepgully)提出的代码。在新代码中,难度在达到某点前以 1 增加,此后开始按分数增量。随着分数增量的增加,所需算力的增加遵循更平稳、更渐进的轨迹,有效地避免了观察到的分片下降。在我们不断努力提高矿工的可用性的过程中,我们添加了在社区节点中启用 API 服务器的选项。启用服务器后,可以更容易地从节点检索基本信息。这些信息包括节点的当前状态、最新的 DS 和 Tx 周期以及 DS 委员会的专门节点。我们将继续构建此功能,在必要时添加更多相关信息。最后,Zilliqa 代码库利用多个开源工具,本着为这些项目做出贡献的精神,核心技术团队帮助修复了 libjson-rpc-cpp 框架中的一个漏洞。Libjson-rpc-cpp 是一个开源框架,它为 C++ 提供了跨平台的 JSON-RPC(远程过程调用协议)支持。该框架以前无法处理某些格式错误的 JSON 信息。我们的代码修复已经提交(参阅https://github.com/cinemast/libjson-rpc-cpp/pull/264),随后被接受并在 libjson-rpc-cpp version 1.2.0 中发布(参阅https://github.com/cinemast/libjson-rpc- cppes/releases/tag/v1.2.0)。启动阶段的结束不会改变现状。当我们努力完善系统时,核心技术团队将继续致力于修复错误、改进和开发新的创新特性。Scilla解释器核心解释器:我们已经在 Scilla 中实现了对外部库的支持。这样,库被导入并构建到一个树结构中,捕获它们的依赖关系。导入库的范围仅限于其直接导入器。如果两个直接相邻导入之间存在名称冲突,则会引发一个错误。添加命名空间以帮助用户避免名称冲突,这是一个待解决的问题。由于情况并不紧急,将稍后处理。我们提醒读者,库支持将便于智能合约开发人员编写更长、更复杂的合约,因为合约的库组件现在可能与非库组件分离,并单独部署。静态分析程序:我们花了一些时间来修复现金流分析程序中的错误,并处理了一些文档问题。我们也一直在研究 gas 分析器,在其中添加了代码,以防止无法解决/无法识别递归。我们还在以稍微不同的方式管理容器,以便为非线性程序识别递归。对于我们的新读者,我们想告诉您,Scilla 的设计使编写静态分析程序变得更加容易。为此,我们一直致力于两个不同的分析器,即现金流分析器和 gas 分析仪。前者检查给定的合同是否正确地处理了资金,而后者则评估为了调用转换而支付的 gas 成本(作为某些输入和合约参数的函数)。未来组件的设计:Scilla 语言和解释器现在已经足够成熟,因此,我们现在正在寻找提高该语言性能和可用性的方法。为此,我们在过去两周一直在积极地探讨几个设计的架构。例如,在可用性方面,我们已经在 Scilla 的基础上为更高级别的语言找到了一些想法,这引发了关于当前和未来 Scilla 面临挑战的讨论。特别是,我们决定向 Scilla 添加过程/子程序,这将限制 Scilla 合约中的代码重复。这也可能导致迭代器被添加到语言中,尽管在此之前需要解决一些设计问题。在性能方面,我们一直在研究为 Scilla 设计一个高效的后端。更多细节将在适当时候公布。Zilliqa新闻报道我们的 CTO 贾瑶琪登上了今年的福布斯「亚洲 30 位 30 岁以下精英榜」,成为该地区在企业技术领域掀起波澜的顶尖科技创新者之一:● 福布斯,2019 年亚洲30位30岁以下精英榜地址:https://www.forbes.com/under30/list/2019/asia/enterprise-technology/#47aaa36169b0在今年的 TOKEN 2049 大会上,我们的 CEO Xinshu 参加了一个关于智能合约平台的小组讨论。如果你没能亲自到现场,可以现在看看视频,听取他对 Zilliqa 作为一个智能合约平台的愿景的看法,他还谈到了 Scilla 的开发,构建和培养一个区块链社区需要什么,以及用例对于进一步获得主流采用的重要性:● YouTube 上关于 Token2049 的视频,构建智能合约平台地址:https://www.youtube.com/watch?v=mCHyzvF4FIw我们的 CEO Xinshu 与 DecryptAsia 一起聊了聊最近推出的主网,他认为区块链行业的未来在于开发能够丰富区块链生态系统的解决方案。● Decryptasia, Ep. #39: Zilliqa — The Sharded Blockchain with Xinshu Dong (CEO Zilliqa)地址:https://www.decrypt.asia/education/episode39/想知道如何成为区块链开发人员吗?我们的应用主管 Edison 从开发人员的角度分享了他作为区块链开发者的经验和行业现状:● People Matters, Here is how the life of a blockchain developer looks like地址:https://www.peoplemattersglobal.com/article/life-at-work/here-is-how-the-life-of-a-blockchain-developer-looks-like-21234我们的开发者市场主管 Saiba 分享了为什么教育是 Zilliqa 团队的一个优先事项,以及他对行业中区块链教育项目现状的看法:● Blockchainreporter, Altcoins: Interview with Saiba Kataruka, Marketing Lead at Zilliqa地址:https://blockchainreporter.net/2019/03/19/altcoins-interview-zilliqa/Cboe 近期宣布将不再增加新的比特币期货合约,我们的商务拓展主管En Hui对此进行了反思,并解释了为什么不必对此感到担忧:● Investing.com, CBOE Suspends Bitcoin Futures; Beginning Of The End For Cryptocurrencies?地址:https://www.investing.com/analysis/cboe-discontinues-bitcoin-futures-conceding-market-to-cme-200399694你听说了吗?我们与 Unstoppable Domains 合作推出了.zil,一个支持多种货币的区块链域名系统。● iHodl, .Zil Launches to Simplify Cryptocurrency Payments地址:https://dailyhodl.com/2019/03/22/zil-launches-to-simplify-cryptocurrency-payments/需要了解我们的共识协议吗?Captain Altcoin 将我们纳入使用拜占庭式实际容错的区块链项目。● Captain Altcoin, What Is Practical Byzantine Fault Tolerance (pBFT)?地址:https://captainaltcoin.com/what-is-practical-byzantine-fault-tolerance-pbft/ ...

April 10, 2019 · 2 min · jiezi

D2 日报 2019年4月10日

???? 新闻➡️ Microsoft Edge Insider 微软正式发布基于 Chrome 的最新 Edge 浏览器 www.microsoftedgeinsider.com➡️ Releases · reduxjs/react-redux 非中文 react-redux 发布 v7 版本 github.com➡️ What to expect in the new Microsoft Edge Insider Channels 非中文 微软正式发布基于 Chrome 的最新 Edge 浏览器 blogs.windows.com???? 分享➡️ 「Vue实践」武装你的前端项目 juejin.im➡️ Abstract Editable Layered Variable Font Effect - Decovar 非中文 可变字体特效文字 codepen.io➡️ 深入理解前端性能监控 - 腾讯新闻前端团队 segmentfault.com➡️ 【React深入】从Mixin到HOC再到Hook - 公众号code秘密花园 segmentfault.com➡️ 你不知道的浏览器页面渲染机制 juejin.im➡️ 淘汰三类人、建议995、优化近20位VP,京东怎么了? www.infoq.cn➡️ 在阿里云做前端 前端早读课 mp.weixin.qq.com➡️ 细谈 vue 核心- vdom 篇 juejin.im➡️ 如何维护更新日志 keepachangelog.com???? 教程➡️ 神经网络与深度学习 nndl.github.io???? 工具➡️ Whimsical 非中文 在线流程图制作工具 whimsical.co➡️ 颜色转换 | Moe Tools 快速转换各种格式的颜色值 www.boxmoe.tools☕️ 更优雅地阅读阅读我们精心排版之后的页面 《D2 日报 2019年4月10日》???? 往期回顾您可以访问下面的链接浏览往期内容,或者模糊检索。https://daily.fairyever.com???? 提交分享你的发现和创造 投稿/提交方式???? 如何获取日报➡️ 官方官方网站 ????RSS ????Github | Releases➡️ 微信公众号扫描下方二维码关注“今日前端”公众号,看日报不迷路!????公众号文章版本经过特殊优化,以提高微信环境内的阅读体验。➡️ 社区主页掘金 ????即刻 ????Segmentfault简书开源中国CSDN ...

April 10, 2019 · 1 min · jiezi

github 代理设置 https/git 速度直接从14k/s 飙升 5m+/s

参考链接: https://gist.github.com/fearb…很多时候我们在使用 github 的时候会出现下载很慢的情况。如果你有代理,可以直接设置代理,来获取更快下载和上传资源的速度。给 git 设置 SOCKS5 代理:使用 https 的时候,就是使用 https 协议复制仓库的时候如: https://github.com/KyleBing/T...git config –global http.proxy ‘socks5://127.0.0.1:1080’git config –global https.proxy ‘socks5://127.0.0.1:1080’也可以直接修改用户主目录下的 .gitconfig 文件[http] proxy = socks5://127.0.0.1:1080[https] proxy = socks5://127.0.0.1:1080在使用 git 开头的路径时,也就是在使用 ssh 通道时如: git@github.com:KyleBing/TouchbarBBT.git打开用户主目录下的 .ssh/config 文件,添加以下内容ProxyCommand nc -x localhost:1080 %h %p效果,速度是真快之前的速度:之后的速度:言外terminal 中设置临时代理直接执行export ALL_PROXY=socks5://127.0.0.1:1080或者在用户主目录下的 .bash_profile 添加别名,这样以后在使用的时候就可以直接输入 proxy了alias proxy=“export ALL_PROXY=socks5://127.0.0.1:1080”

April 10, 2019 · 1 min · jiezi

小白文 初识git-版本分支管理及远程仓库提交

为什么使用git有一个项目a,已经完成了基本的功能,测试下来是稳定的,接下来想增加新的功能,并用对其完善,但这个过程中可能会出现bug,甚至影响到全局这个时候,我们就希望保存一个稳定版本的文件,另外复制一份文件进行改进,这样即便遇到问题也可以回到稳定的状态,并可以进行对比来进行dbug在学习版本控制工具前,方法是复制文件夹,然后在新的文件夹中进行修改,但是明显这样会造成多余的文件夹,管理极为混乱所以就需要我们的版本分支管理工具git登场了安装从官网下载对应的exe进行安装即可只要这边改成第一个,保证安全性,其他就一路next就可以了配置$ git config –global user.name “name” //填名字$ git config –global user.email 123@163.com //邮箱初次提交在项目文件夹中右键菜单,Git Bash here或者在其他地方Git Bash here之后,命令行里输入cd 路径名转到项目文件夹中$ git init //初始化仓库下一步就要把文件全部提交到仓库的暂存区$ git add . //可以把.改成要提交的文件名来单独提交不过在这之前,先要确定哪些文件不要提交通过IDE(不能直接在文件夹右键新建)(我用的vscode,在命令行输入$ Code .gitignore)新建一个.gitignore文件,在里面写要忽略的文件//忽略规则• bin/: 忽略当前路径下的bin文件夹,该文件夹下的所有内容都会被忽略,不忽略 bin 文件• /bin: 忽略根目录下的bin文件• /.c: 忽略 cat.c,不忽略 build/cat.c• debug/.obj: 忽略 debug/io.obj,不忽略 debug/common/io.obj 和 tools/debug/io.obj• /foo: 忽略/foo, a/foo, a/b/foo等• a//b: 忽略a/b, a/x/b, a/x/y/b等• !/bin/run.sh: 不忽略 bin 目录下的 run.sh 文件• .log: 忽略所有 .log 文件• config.php: 忽略当前路径的 config.php 文件然后要把暂存区的文件里提交到正式的仓库里$ git commit -m ‘这里可以加提交的注释’如果.gitignore文件没有在提交前建立,或者不小心提交了不想要提交的文件,那可以通过下面的命令行进行取消$ git reset 文件名 取消暂存区的文件 $ git rm -r –cached 文件名 移除正式仓库里的文件,加上–cached就不会把本地的文件删除提交之后,或者未提交时,都可以通过这句来查看仓库目前的状态是否有未跟踪的文件,或者暂存区里有尚为正式提交的文件,都会有所显示$ git status如果工作目录显示是干净的,也就完成了我们的初次提交On branch masternothing to commit, working directory clean在提交中,可能会遇到这样的问题warning: LF will be replaced by CRLFwindows中的换行符为 CRLF, 而在linux下的换行符为LF所以在执行add . 时出现提示解决方法:$ git config –global core.autocrlf false //禁用自动转换查看提交历史$ git log$ git log -a //更详细将稳定版提交到github在github的个人主页中,新建立一个仓库复制仓库页面的url在Git Bash中执行$ git clone url 这样就会在Git Bash所打开的地方,建立出一个新的文件夹,里面会有网上仓库的内容(如果在建立的时候有勾选Readme说明文件的话,就可以看到它)然后把稳定版里的所有文件复制到这个新文件中进行之前初次提交的操作$ git add .$ git commit -m ‘’$ git commit -a -m ’’ //把上面两句简写到一起然后进行仓库的远程提交$ git push输入账号密码后,即把文件提交到了github上的仓库中分支与合并回到我们最初问题上来在保存了稳定版本到仓库后我们可以创建一个分支$ git branch fen //创建分支$ git checkout fen //切换到新的这个分支上$ git checkout -b fen //也可以两句合写然后就可以对其中的文件进行修改可以随时切换回主线,git会把文件都还原成稳定版的状态$ git checkout master文件修改修改了文件内容之后如果尚未提交暂存,想查看对比仓库里的文件的修改之处 :$ git diff如果已经提交到暂存,想查看对比仓库里的文件的修改之处 :$ git diff –staged如果此时又对文件内容做了修改再使用下面这句$ git diff 显示的就是文件和暂存区内文件的对比(不是仓库了)查看文件的具体状态$ git status -sM //已经提交到暂存的修改文件 M //尚为提交到暂存的修改文件MM //已经提交到暂存,并在暂存后继续修改的文件A //新提交到暂存的文件?? //尚为跟踪的文件分支合并查看分支情况$ git branch fen master在修改完这个分支之后,测试为稳定,希望将其合并到主线上,进行版本更新$ git checkout master //切换回主线$ git merge fen //把支线合并过来$ git merge -d fen //删除此分支至此,就完成了一次工作流程目前用到的都只是个人的版本管理,没有涉及多人协作更具体的学习还是要参照官方文档 https://git-scm.com/book/zh/v… ...

April 10, 2019 · 1 min · jiezi

“龙井”开箱评测 |Alibaba Dragonwell 新手上路指南

作者|阿里云智能事业群 高级技术专家 陆传胜阿里巴巴有着最丰富的 Java 应用场景,覆盖电商,金融,物流等众多领域,是世界上最大的 Java 用户之一。 2019 年 3 月 21 日,阿里巴巴在北京阿里云峰会上正式宣布开源了 Alibaba Dragonwell 8 产品,并建立了 Alibaba Dragonwell 社区来为全球 Java 用户,特别是中文社区的 Java 用户提供长期支持的 JDK 产品。自宣布开源以来,Alibaba Dragonwell 8 受到了国内外 Java 开发者的关注,今天这篇文章就来详解 Alibaba Dragonwell8 的快速安装和使用,同时列出了参与社区建设的几种方式,期望为那些即将安装及使用 Alibaba Dragonwell 8 的开发者提供参考。Alibaba Dragonwell 8 介绍Alibaba Dragonwell 8 是一款免费的 OpenJDK 发行版。它提供长期支持,包括性能增强和安全修复。Alibaba Dragonwell 8 目前支持 X86-64/Linux 平台,在数据中心大规模 Java 应用部署情况下, 可以大幅度提高稳定性、效率以及性能。Alibaba Dragonwell 8 是 OpenJDK 的下游(friendly fork),使用了和 OpenJDK 一样的 licensing。Alibaba Dragonwell 8 与 Java SE 标准兼容,用户可以使用 Alibaba Dragonwell 8 开发和运行 Java 应用程序。此次开源的 Alibaba Dragonwell 8 是阿里巴巴内部 OpenJDK 定制版 AJDK 的开源版本, AJDK 为在线电商,金融,物流做了结合业务场景的优化,运行在超大规模的,100,000+ 服务器的阿里巴巴数据中心。安装 Alibaba Dragonwell 8目前 Alibaba Dragonwell 8 只支持 Linux x86-64 平台,并且提供了二进制的预编译 JDK 包,您可以通过下面的简单两步安装 Alibaba Dragonwell 8。从 Github 上面 Alibaba Dragonwell 8 项目的下载页面下载预编译的二进制 JDK 包。下载页面链接 https://github.com/alibaba/dragonwell8/releases 将下载下来的 tar 包解压到目标安装目录即可。安装完毕后,只需要将应用引用 的 JAVA_HOME 指向 Alibaba Dragonwell 8 的安装目录就可以使用了。我们以Tomcat8.5.39 版本为例,为了让 Tomcat 运行在 Alibaba Dragonwell 8上面,只需要在启动Tomcat时使用如下命令:JAVA_HOME=/path/to/dragonwell8/installation sh tomcat/bin/catalina.sh start为了确认是运行在 Alibaba Dragonwell 8上面,可以进一步通过给 java 命令添加 -showversion 参数来打印 JDK 版本信息加以判断。JAVA_HOME=/path/to/dragonwell8/installation JAVA_OPTS="-showversion" sh tomcat/bin/catalina.sh start启动完毕后在 tomcat/logs/catalina.out 文件的开头,可以看到 Alibaba Dragonwell 8 的版本信息使用 Alibaba Dragonwell 8 专有特性在 8.0-preview 这个版本中, Alibaba Dragonwell 8 提供了两个在阿里巴巴的生产环境中进行过广泛验证的特性:JWarmUp 和 Java Flight Recorder。这两个特性都已经在上游 OpenJDK 社区提交了 JEP 或 patch,在上游合并完成之前,我们希望让 Alibaba Dragonwell 8 的用户可以提前使用到这两个特性。JWarmUp 快速预热 Java 应用OpenJDK 使用了 JIT(Just-in-time) 即时编译技术,可以动态的把 Java 字节码编译成高度优化过机器码,提高执行效率,但在编译之前,Java 代码是以相对低效的解释器模式执行的。在应用启动完成后、业务流量刚进来的短时间内,容易出现的状况是大量 Java 方法开始被 JIT 编译,同时业务请求被较慢的解释器模式执行,最终的结果就是系统负载飙高,可能导致很多用户请求超时。为了解决这个问题,之前的很多做法是使用模拟流量来提前预热应用,JWarmUp 特性提供了一个新的选择,就是利用 Java 虚拟机前一次执行编译得记录来预热本次应用的执行。JWarmUp 的原理如下图所示:一个典型的应用场景是当应用需要发布新版本的时候,首先 JWarmUp 在 Beta 环境(或者有着和生产环境类似流量的其他场景)的单台机器上短时间执行 Java 应用,并记录、收集这段时间里面 JIT 编译器所做动作的一些元数据。然后会把这些元数据复制到生产环境的每一台包含了新版本代码的机器/容器里面。最后在生产环境机器中通过 JWarmUp 参数加载 beta 环境生成的元数据,来指导生产环境的机器在启动应用的过程中就完成 JIT 预热。这样当用户请求进入的时候,应用就会处于性能最高的峰值状态。收集预热数据还以 Tomcat 应用为例,可以添加下面的命令行参数来在 beta 环境中收集 JIT 编译时生成的元数据,其中参数 -XX:CompilationWarmUpLogfile= 指定的就是生成的 JWarmUp 文件的路径。JAVA_HOME=/path/to/dragonwell8/installation JAVA_OPTS="-XX:ReservedCodeCacheSize=512m -XX:CompilationWarmUpLogfile=$PWD/jwarmup.log -XX:+CompilationWarmUpRecording -XX:+CompilationWarmUp -XX:-TieredCompilation -XX:+DeoptimizeBeforeWarmUp -XX:CompilationWarmUpDeoptTime=30 -XX:+PrintCompilationWarmUpDetail" sh bin/catalina.sh start生成之后可以把这个文件通过 OSS、SFTP 等方式传输到生产环境的机器上。使用记录的数据来预热 Java 应用在生产环境的机器上,只需要使用下面的参数,就可以利用之前的预热数据来启动一个新的 Tomcat 实例,其中参数 -XX:CompilationWarmUpLogfile= 制定的就是需要被加载的 JWarmUp 文件路径,这个文件应该是上一步收集预热数据时从 beta 环境复制过来的。JAVA_HOME=/path/to/dragonwell8/installation JAVA_OPTS="-XX:ReservedCodeCacheSize=512m -XX:CompilationWarmUpLogfile=$PWD/jwarmup.log -XX:+CompilationWarmUp -XX:-TieredCompilation -XX:+DeoptimizeBeforeWarmUp -XX:CompilationWarmUpDeoptTime=30 -XX:+PrintCompilationWarmUpDetail" sh bin/catalina.sh start使用 Java Flight Recorder 分析 Java 应用性能JFR(Java Flight Recorder)是 JVM 内置的基于事件的性能分析特性,这是 Oracle JDK7u4 版本开始提供的商业特性,2018 年的时候在 JDK11 上开源了这个特性,但是一直没有针对 JDK8 版本的支持。阿里巴巴和 RedHat、Azul、Amazon 等公司一起合作尝试把这个特性移植回 JDK8上,不过该 patch 暂时还没有合并回 OpenJDK8u仓库,我们在 Alibaba Dragonwell 8 中提供了 Alibaba 移植的 JFR 版本,用于帮助用户提前获取这方面的支持。JFR 的用法很简单,用户使用命令行参数或者 jcmd 命令控制 HotSpot 输出性能数据到文件中,然后就能使用开源的 jmc 工具在图形界面中打开、分析生成的数据文件了。使用 JFR 收集性能数据在 Alibaba Dragonwell 8中,默认情况下 JFR 特性是处于关闭的状态,必须添加命令行参数 -XX:+EnableJFR 来允许使用 JFR 特性。 Alibaba Dragonwell 8 提供了不同的方式来使用 JFR 采集性能数据。应用可以可以通过命令行参数指定 JFR 再启动后立马开始采集数据,这个对于诊断启动阶段的问题会很有帮助。下面的示例命令会在 Java 进程的 JFR 模块初始化后就开始收集 JFR 数据,持续一分钟,并且把数据都输出到名为rec.jfr 的文件中。JAVA_HOME=/path/to/dragonwell8/installation JAVA_OPTS="-XX:+EnableJFR -XX:StartFlightRecording=duration=1m,filename=rec.jfr" sh bin/catalina.sh start应用也可以只添加 -XX:+EnableJFR ,然后通过 jcmd 命令在应用启动后的任意时间点开始采集数据,这种情况更加灵活可控,可以满足随时随地进行分析的需求。以 Tomcat 为例,启动 Tomcat 的命令可以是:JAVA_HOME=/path/to/dragonwell8/installation JAVA_OPTS="-XX:+EnableJFR" sh bin/catalina.sh start当需要收集数据进行分析时,只需要使用目标 Tomcat 进程的 PID 来执行 JFR 对应的 jcmd 命令即可。以 Tomcat 为例,如果需要在指定时刻开始收集 10 秒的数据,那么触发的命令如下:$ ps ax | grep tomcat 77522 pts/18 Sl+ 0:08 /home/chuansheng.lcs/dw_test/apache-tomcat-8.5.39/../j2sdk-image/bin/java -Djava.util.logging.config.file=/home/chuansheng.lcs/dw_test/apache-tomcat-8.5.39/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -XX:+EnableJFR -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /home/chuansheng.lcs/dw_test/apache-tomcat-8.5.39/bin/bootstrap.jar:/home/chuansheng.lcs/dw_test/apache-tomcat-8.5.39/bin/tomcat-juli.jar -Dcatalina.base=/home/chuansheng.lcs/dw_test/apache-tomcat-8.5.39 -Dcatalina.home=/home/chuansheng.lcs/dw_test/apache-tomcat-8.5.39 -Djava.io.tmpdir=/home/chuansheng.lcs/dw_test/apache-tomcat-8.5.39/temp org.apache.catalina.startup.Bootstrap start 98451 pts/22 S+ 0:00 grep –color=auto tomcat$ dragonwell8_home/bin/jcmd 77522 JFR.start duration=10s filename=$PWD/rec3.jfr77522:Started recording 3. The result will be written to:/home/my/workdir/rec3.jfr10 秒之后可以看到生成了 JFR 数据文件/home/my/workdir/rec3.jfr,使用 JMC 即可进行分析。也可以不指定收集数据的时间,直接启动 JFR 收集,并且在需要的时候手动把所有生成的数据一次性 dump 到文件,$ dragonwell8_home/bin/jcmd 2823 JFR.start filename=$PWD/rec4.jfr2823:Started recording 4. No limit specified, using maxsize=250MB as default.Use JFR.dump name=4 to copy recording data to file.$ dragonwell8_home/bin/jcmd 2823 JFR.dump name=4 filename=rec4.jfr2823:Dumped recording “Recording-4”, 332.7 kB written to:/path/to/my/workdir/rec4.jfr使用 JMC 分析性能JFR 记录 Java 应用性能数据的输出是一个二进制的文件,我们借助于 JMC(Java Mission Control) 工具可以在图形化界面里面分析具体的性能数据。这个工具是开源产品,没有包括在 Alibaba Dragonwell 8里面,需要到 OpenJDK 的官方网站下载使用,https://jdk.java.net/jmc/。请注意, Alibaba Dragonwell8 生成的JFR数据文件需要 7.0 或更高版本的 JMC 工具来分析。打开 JMC 后,可以点击左侧的详细类别来详细分析采样时间段内发生的各种事件。诊断调试支持 Alibaba Dragonwell 8 还内置一些方便的诊断特性,主要包括大对象分配报警可以通过新的 JVM 参数"-XX:ArrayAllocationWarningSize=",比如下面代码中分配了比较大的数组public static void main(String[] args) { doAlloc(32 * 1024 * 1024 + 1);}private static Object doAlloc(int size) { return new byte[size];}执行时如果添加 ArrayAllocationWarningSize 选项就会打印出分配该数组时的 Java 堆栈详细的 ParNew GC 日志支持 Alibaba Dragonwell 8 默认使用了 CMS (Concurrent Mark Sweep) 算法,新生代使用了 ParNew 算法,所以内置两个针对 ParNew GC 日志的增强可以通过 jinfo 工具设置 PrintYoungGenHistoAfterParNewGC 选项来在下一次 Young GC 结束的时候打印新生代的对象类型直方图。命令如下jinfo -flag +PrintYoungGenHistoAfterParNewGC <pid>打印完成后,这个选项会被重置回 false 状态,防止过多的输出,一个典型的输出例子如下:可以通过-XX:+PrintGCRootsTraceTime 来打印处理每一类 GC 根集所花费的详细 CPU 时间,输出示例如下:精简版 HeapDump 支持 Alibaba Dragonwell 8 的 jmap 工具支持一个新的 dump 选项“mini”可以在做 heapdump 的时候跳过所有的原始类型数组的内容,从而大大减小生成的 heapdump 文件大小,这对于只需要排查类型、对象关系的场景会比较有帮助。示例命令如下:本文作者:中间件小哥阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

April 9, 2019 · 3 min · jiezi

在GitHub上新建仓库并与本地Git项目绑定最简单步骤

!!!实际操作经验,实测有效!!!1、github上新建一个项目成功后,有提示两个步骤: git remote add origin git@github.com:username/projectname.git (username、projectname换成你自己的)git push -u origin master接下来的步骤完全是照这两步来的不过如果本地没有.git文件夹,在执行‘git push -u origin master’前:自己先git init,git -A(自己定好.gitignore文件先),git commit。最后皆大欢喜。

April 9, 2019 · 1 min · jiezi

D2 日报 2019年4月9日

???? 新闻➡️ WeGame X 腾讯全球版游戏平台WeGame已推出,名为WeGame X。可以下载试用国际版,里面已有17个中国自主研发的游戏 www.wegamex.com.hk➡️ cn.vuejs.org 讨论并征集关于 attribute 和 property 的译法 github.com???? 开源项目➡️ l-hammer/v-track watch 0 star 2 fork 0 ????一个基于Vue指令实现的埋点插件~ github.com➡️ visionmedia/node-progress watch 32 star 2144 fork 187 用于 nodejs 的灵活的 ASCII 进度条 github.com➡️ chalk/chalk 非中文 watch 133 star 11797 fork 440 一个命令行交互的着色工具。在命令行支持的情况下,可以支持最多16位色域,一般可以配合 console.log 使用 github.com➡️ SBoudrias/Inquirer.js 非中文 watch 132 star 9816 fork 614 在终端中创建交互式问答,例如 vue cli 创建项目时的用户选项 github.com➡️ sindresorhus/ora 非中文 watch 46 star 4606 fork 168 终端 loading 图标 github.com➡️ xcatliu/typescript-tutorial watch 97 star 3005 fork 392 TypeScript 入门教程 github.com➡️ chaosblade-io/chaosblade watch 46 star 617 fork 70 阿里开源混沌工程工具。该项目是遵循混沌工程(Chaos Engineering)原理的实验工具,用于模拟常见的故障场景,帮助提升分布式系统的可恢复性和对故障的容错性 github.com➡️ node-modules/address 非中文 watch 13 star 95 fork 14 获取 IP 和 MAC 地址的库 github.com???? 分享➡️ CSS中如何实现伪随机? juejin.im➡️ 跨域多方位解决方案 juejin.im➡️ 中国第五届CSS大会 中国第五届CSS大会视频和 PPT www.yuque.com➡️ 【前端词典】4 种滚动吸顶实现方式的比较 juejin.im➡️ 2019年Vue生态圈调查:92%的开发者将继续用Vue mp.weixin.qq.com➡️ 聊一聊前端换肤 juejin.im???? 网站➡️ Tetr.js 一个在线玩俄罗斯方块的网站,可以自己调整快捷键,有多种模式可玩 farter.cn➡️ Koalas to the Max dot Com 非中文 一个鼠标移动会进行圆圈分裂的网站 www.koalastothemax.com???? 工具➡️ Flawless 非中文 当产品开发完成,进行功能和设计走查时,往往需要不断截图然后发送到电脑再进行标记,非常繁琐。Flawless 通过 AirPlay 将屏幕投射到电脑,在电脑上就可以快速截图和标记,再以链接形式分享给他人 flawlessapp.io➡️ Backery.io - Web app deployments cheap and easy 非中文 带有数据库和免费备份的PaaS backery.io➡️ Similarsites.com 非中文 帮你发现相似的网站 www.similarsites.com???? 设计➡️ 澳门图书馆周主题海报设计 weibo.com☕️ 更优雅地阅读阅读我们精心排版之后的页面 《D2 日报 2019年4月9日》???? 往期回顾您可以访问下面的链接浏览往期内容,或者模糊检索。https://daily.fairyever.com???? 提交分享你的发现和创造 投稿/提交方式???? 如何获取日报➡️ 官方官方网站 ????RSS ????Github | Releases➡️ 微信公众号扫描下方二维码关注“今日前端”公众号,看日报不迷路!????公众号文章版本经过特殊优化,以提高微信环境内的阅读体验。➡️ 社区主页掘金 ????即刻 ????Segmentfault简书开源中国CSDN ...

April 9, 2019 · 1 min · jiezi

gitbook 入门教程之发布电子书

输出目标文件语法格式: gitbook build [book] [output]默认情况下,gitbook 输出方式是静态网站,其实 gitbook 的输出方式有三种: website, json,和 ebook.只不过另外两种不是很常用,更多情况下我们是使用静态网页搭建个人官网,或托管到第三方平台,或部署到私有云服务器,但不管怎么样,还是离不开生成这一步.示例:# 默认输出格式: website$ gitbook build –format=website# 更改输出格式: json$ gitbook build –format=json# 更改输出格式: ebook$ gitbook build –format=ebook默认情况下输出目录: _book/,整个项目的入口文件是: index.html集成 github 网站本教程的电子书源码和输出文件均托管到 github 网站,所以这里介绍下如何利用 Github Pages 静态网页服务与 gitbook 进行集成.什么是 GitHub Pages ?Github Pages 是 github 网站推出的一种免费的静态网页托管服务,适合搭建静态的项目主页或个人官网.其中,网站项目的源码直接托管在 github 仓库中,当仓库文件更新后,该仓库所关联的网站自动更新,从而实现了源码与官网的联动更新.如果想了解更多详情,请参考官网: https://pages.github.com/怎么做 GitHub Pages ?每个账号有且只有一个主页站点,但允许无限制多的项目站点.啥是主页站点,项目站点又是啥?别急,让我先举个例子看一下最终效果.假如用户名: zhangsan 名下有四个公开仓库,一个仓库名叫做: zhangsan.github.io,另外三种分别是: project01,project02,project03 .如果想要对外暴露上述四个仓库作为我们的静态网站,那么最终效果就是下面这样的.主页站点: https://zhangsan.github.io项目01站点: https://zhangsan.github.io/project01项目02站点: https://zhangsan.github.io/project02项目03站点: https://zhangsan.github.io/project03注意将 zhangsan 替换成自己的 github 用户名,否则八成是打不开网站,除非真的有 zhangsan 这个用户.其实上述规则很好理解,github 网站作为一个托管中心,有成千上万的用户在使用 github 并且每个用户的用户名都是唯一并且不同的,因此 *.github.io 通配符域名刚好充当命名空间.可以预料的是,不仅仅有 <username>.github.io 这种二级域名,说不定还有 api.github.io,docs.github.io 等等,毕竟只需要购买 .github.io 通配符域名证书就可以支持任意多的二级域名了,感谢 github 赠送我们免费的 https 网站.说到这里,不得不吐槽下 gitbook 的命名空间策略了,gitbook 也有自己的电子书托管服务,但访问地址是 <username>.gitbook.io/<namespace> .很显然,gitbook 没有区分主页站点和项目站点,相当于全部都是项目站点,缺少主次之分.闲言少叙,既然知道了输入内容和输出效果,那么接下来的任务就是了解中间过程了,让我们一起探讨下怎么发布网站吧!主页站点创建 <username>.github.io 公开仓库前往 https://github.com/ 网站创建名为 <username>.github.io 的公开仓库.比如我的用户名是: snowdreams1006 ,那么我的主页站点仓库就是: snowdreams1006.github.io创建首页 index.html 文件不管是在线直接创建 index.html 还是克隆到本地创建 index.html ,最终的 <username>.github.io 仓库一定要有 index.html 首页文件.示例:# 克隆到本地$ git clone https://github.com/username/username.github.io# 切换到项目$ cd username.github.io# 创建 index.html 文件$ echo “Hello World” > index.html# 推送到远程仓库$ git add –all$ git commit -m “Initial commit”$ git push -u origin master访问主页站点 https://username.github.io打开浏览器,输入网址: https://username.github.io 访问主页站点,显示的内容正是我们刚刚提交的 index.html 文件内容.如果没有正常显示,清除浏览器缓存强制刷新试试看!项目站点相比主页站点来说,项目站点命名比较随意了,作为静态网站不可或缺的文件仍然是 index.html.创建首页 index.html 文件创建首页文件并添加测试内容,方便待会在线访问项目站点测试是否部署成功.设置 GitHub Pages 选项点击仓库首页右上方设置(Settings)选项卡,往下翻到 GitHub Pages 选项,选择源码目录,根据实际情况选择源码来源于 master 分支还是其他分支或者docs/ 目录.方便起见,选择第一个 master 分支即可,注意下面的主题和这一步的来源只能两者选其一,否则主题优先级更高!访问主页站点 https://username.github.io/<repository>打开浏览器,输入网址: https://username.github.io/repository 访问项目站点,显示的内容正是我们刚刚提交的 index.html 文件内容.如果没有正常显示,清除浏览器缓存强制刷新试试看!如何集成 gitbook ?我们已经知道 Github Pages 是提供静态网站的免费托管,而 gitbook 默认生成的内容就是静态网站,两者如何结合自然不用我多说了吧?gitbook 默认输出目录 _book/ 包括了静态网站所需的全部资源,其中就包括 index.html 首页文件.因此我们只需要每次生成后将 _book/ 整个目录复制到项目根目录,那么推送到远程仓库时自然就是输出后静态网站了啊!示例:# 生成静态网站$ gitbook build# 复制到项目根目录$ cp -r _book/ .# 添加到本地版本库$ git add .$ git commit -m “publish”# 推送到远程仓库$ git push origin master现在登录 github 网站看一下静态网站是否成功上传以及访问主页站点或项目站点看一下最新内容是否成功渲染吧!小结本节我们学习 gitbook 有三种输出方式,其中默认的网页输出最为常用.除此之外,还讲解了如何与 github pages 进行结合,从而实现源码和网站的自动更新维护.如果源码没有托管到 github 这种第三方服务商,你也可以搭建自己的服务器,比如将 _book/ 目录全部扔到 nginx 服务器做静态资源服务器等.毕竟,源码和输出内容都在你手中,想怎么玩还不是自己说了算? ...

April 9, 2019 · 1 min · jiezi

基于jenkins搭建CICD

本文主要介绍通过jenkins参数化构建搭建CICD(持续集成/持续交付),主要介绍jenkins参数化构建配置,jenkins本身搭建请查看官方文档涉及到的插件:description setter plugin 、user build vars plugin、qunar plugin一、最终效果二、参数化配置点击配置,勾选参数化构建点击添加参数,有下面这些参数

April 8, 2019 · 1 min · jiezi

程序 + 音乐: 我的自由钢琴开发历程

原文链接Hate 996? Come Here & Relax最近用Vue + Tone.js做了一款钢琴类web应用,名字定为自由钢琴(AutoPiano),人生如音乐,欢快且自由。此文权当作该项目的总结和分享项目简介自由钢琴(AutoPiano)是利用HTML5技术开发的在线钢琴应用,致力于为钢琴爱好者、音乐爱好者以及其他所有的创造者提供一个优雅、简洁的平台,在学习工作之余可以享受钢琴、音乐的美好。就类似于多年前Flash开发的钢琴游戏,自由钢琴只是换了H5的技术,同时支持了钢琴曲的自动播放功能。AutoPiano支持键盘按键和鼠标点击播放,同时琴键上会有按键和音名提示。另外,AutoPiano还有教学的功能,一种方式是快速入门,通过简易的谱子按键进行演奏,另一种是演奏示例,通过钢琴曲的自动播放来达到演示的目的。目前这两个功能都在持续完善中,如下图所示:体验地址: http://crystalworld.gitee.io/…项目地址: https://github.com/WarpPrism/…开发这样的应用需要乐理知识吗?当然。基本的乐理知识还是要知道的,比如 CDEFGAB 音名、五线谱、调式、节奏等等还是要懂一点的。篇幅所限,这里就不展开讨论了,推荐两个网站:https://www.bilibili.com/vide…https://www.cnblogs.com/devym…其他的就是编程知识了,以及如何将乐理知识转化为程序逻辑。AutoPiano目前采用的技术架构是vue框架 + tone.js。钢琴界面效果是怎么写的?可以用CSS或贴图。笔者这里直接用css实现了,考虑到钢琴有黑键和白键,且黑键和白键有序地排列成 7:5的模式,所以实现起来并不复杂。<div class=“piano-key-wrap”> <div class=“piano-key wkey” v-for=“note in Notes” :key=“note.keyCode” :data-keyCode = “note.keyCode” v-if=“note.type==‘white’” @click=“clickPianoKey($event, note.keyCode)"></div> <div class=“bkey-wrap bkey-wrap1”> <div class=“piano-key bkey” v-for=“note in Notes” :key=“note.keyCode” :data-keyCode = “note.keyCode” v-if=“note.type==‘black’ && note.id >= 36 && note.id <= 40” @click=“clickPianoKey($event, note.keyCode)"></div> </div></div>.piano-wrap { width: 90%; margin: 20px auto; .piano-key-wrap { width: 100%; background: @dark; overflow: hidden; position: relative; .wkey { display: inline-block; width: 2.775%; height: 100%; margin: 0 auto; background: linear-gradient(white 10%, rgb(251, 251, 251) 92%, rgb(220, 220, 220) 93%, white 97%); border: solid 1px @dark; border-radius: 0 0 5px 5px; position: relative; &:active { background: linear-gradient(#eee 10%, #ddd 60%, #bbb 93%, #ccc 97%); } } .wkey-active { background: linear-gradient(#eee 10%, #ddd 60%, #bbb 93%, #ccc 97%); } .bkey-wrap { width: 20%; height: 0; position: absolute; top: 0; } .bkey-wrap1 {left: 0;} .bkey-wrap2 {left: 19.5%;} .bkey-wrap3 {left: 39%;} .bkey-wrap4 {left: 58.3%;} .bkey-wrap5 {left: 77.7%;} .bkey { display: inline-block; width: 10%; height: 70%; background: linear-gradient(#000 10%, rgb(86, 86, 86) 85%, #000 90%); border-radius: 0 0 3px 3px; position: absolute; top: 0; overflow: hidden; &:active { background: linear-gradient(rgb(86, 86, 86) 10%, #000 90%, #222 100%); } } .bkey-active { background: linear-gradient(rgb(86, 86, 86) 10%, #000 90%, #222 100%); } .bkey:nth-child(1) {left: 9%;} .bkey:nth-child(2) {left: 23%;} .bkey:nth-child(3) {left: 50%;} .bkey:nth-child(4) {left: 65%;} .bkey:nth-child(5) {left: 79%;} }}codepen上也有很多这样的例子供参考,不一定采用上述实现:https://codepen.io/search/pen…相信只要合理地控制css变量和数值,大家能做出更好的 Piano 界面。如何实现单个音符的播放?实现音频播放,最简单的就是利用HTML5 中的 audio 标签,通过触发audio的play和pause方法,实现对音频的控制,笔者一开始就是这么实现的。// <div class=“audios-wrap” id=“audios-wrap”>// <audio src=”” id=“preloadAudio” ref=“preloadAudio”></audio>// </div>// 预先为每个音符都建立一个audio元素initAudioDom() { var vm = this for (let i = 0; i< vm.Notes.length; i++) { var note = vm.Notes[i] $(’.audios-wrap’).append(&lt;audio src='${note.url}' hidden='true' data-id='audio${i}' class='audioEle'&gt;); }},// 触发某个audio元素的播放playNote(url) { var vm = this if (!url || typeof url != ‘string’) return; var audios = $(’.audioEle’); for (let i = 0; i< audios.length; i++) { let audio = audios[i]; if (audio.src.indexOf(url) > -1) { var cloneAudioNode = audio.cloneNode() cloneAudioNode.play() cloneAudioNode.remove() break; } }}上述是我的第一种实现方式,即不同音符触发不同audio的播放。之后也许是出于好奇,尝试了 Tone.js,通过Tone.js + 内置采样器实现对音频播放更有效的控制,当然,其提供的很多复杂功能都还没用上。。。// 初始化合成器this.synth = SmapleLibrary.load({ instruments: “piano”}).toMaster()// 合成器触发音频释放playNote(notename = ‘C4’, duration = ‘2n’) { if (!this.synth) return this.synth.triggerAttackRelease(notename, duration);}嗯,现在的代码就符合音乐美学和代码美学了,美滋滋。当然笔者也期望Tone.js能快点完善中文文档,不然上手还是很吃力的,感兴趣的小伙伴可以先去其官网研究一番。关于钢琴曲的自动播放这一部分应该是开发整个应用最难的地方了,因为音乐或者说乐谱本身是相当复杂的,根据百度百科的描述,五线谱起源于希腊,历经上千年不断完善才成为现在的乐谱标准。而简谱的出现则要晚的多,但依然五脏俱全,可以说,简谱也不简单。笔者的实现思路是,以一种乐谱格式为载体,将乐谱转换为一种程序可识别的格式,然后导入到程序中进行播放,这种可识别格式如下所示,也是目前所采用的: { name: ‘小星星’, step: ‘C’, speed: ‘100’, playState: ‘’, mainTrack: [‘1(1)’,’ 1(1)’,’ 5(1)’,’ 5(1)’,’ 6(1)’,’ 6(1)’,’ 5(2)’,’ 4(1)’,’ 4(1)’,’ 3(1)’,’ 3(1)’,’ 2(1)’,’ 2(1)’,’ 1(2)’,’ 5(1)’,’ 5(1)’,’ 4(1)’,’ 4(1)’,’ 3(1)’,’ 3(1)’,’ 2(2)’,’ 5(1)’,’ 5(1)’,’ 4(1)’,’ 4(1)’,’ 3(1)’,’ 3(1)’,’ 2(2)’,’ 1(1)’,’ 1(1)’,’ 5(1)’,’ 5(1)’,’ 6(1)’,’ 6(1)’,’ 5(2)’,’ 4(1)’,’ 4(1)’,’ 3(1)’,’ 3(1)’,’ 2(1)’,’ 2(1)’,’ 1(2)’, ‘1<(1)’, ‘1<(1)’, ‘5<(1)’, ‘5<(1)’, ‘6<(1)’, ‘6<(1)’, ‘5<(2)’, ‘4<(1)’, ‘4<(1)’, ‘3<(1)’, ‘3<(1)’, ‘2<(1)’, ‘2<(1)’, ‘1<(2)’, ‘5<(1)’, ‘5<(1)’, ‘4<(1)’, ‘4<(1)’, ‘3<(1)’, ‘3<(1)’, ‘2<(2)’, ‘5<(1)’, ‘5<(1)’, ‘4<(1)’, ‘4<(1)’, ‘3<(1)’, ‘3<(1)’, ‘2<(2)’, ‘1<(1)’, ‘1<(1)’, ‘5<(1)’, ‘5<(1)’, ‘6<(1)’, ‘6<(1)’, ‘5<(2)’, ‘4<(1)’, ‘4<(1)’, ‘3<(1)’, ‘3<(1)’, ‘2<(1)’, ‘2<(1)’, ‘1<(2)’], backingTrack: [‘1>(0.5)’, ‘5>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’, ‘1>(0.5)’, ‘5>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’, ‘1>(0.5)’, ‘6>(0.5)’, ‘4>(0.5)’, ‘6>(0.5)’, ‘1>(0.5)’, ‘5>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’, ‘1>(0.5)’, ‘6>(0.5)’, ‘4>(0.5)’, ‘6>(0.5)’, ‘1>(0.5)’, ‘5>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’, ‘7>>(0.5)’, ‘5>(0.5)’, ‘2>(0.5)’, ‘5>(0.5)’, ‘1>(0.5)’, ‘5>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’, ‘1>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’,’ 1(0.5)’, ‘1>(0.5)’, ‘4>(0.5)’, ‘6>(0.5)’,’ 1(0.5)’, ‘1>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’,’ 1(0.5)’, ‘5>>(0.5)’, ‘7>>(0.5)’, ‘2>(0.5)’, ‘5>(0.5)’, ‘1>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’,’ 1(0.5)’, ‘1>(0.5)’, ‘4>(0.5)’, ‘6>(0.5)’,’ 1(0.5)’, ‘1>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’,’ 1(0.5)’, ‘5>>(0.5)’, ‘7>>(0.5)’, ‘2>(0.5)’, ‘5>(0.5)’, ‘1>(0.5)’, ‘5>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’, ‘1>(0.5)’, ‘5>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’, ‘1>(0.5)’, ‘6>(0.5)’, ‘4>(0.5)’, ‘6>(0.5)’, ‘1>(0.5)’, ‘5>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’, ‘1>(0.5)’, ‘6>(0.5)’, ‘4>(0.5)’, ‘6>(0.5)’, ‘1>(0.5)’, ‘5>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’, ‘7>>(0.5)’, ‘5>(0.5)’, ‘2>(0.5)’, ‘5>(0.5)’, ‘1>(0.5)’, ‘5>(0.5)’, ‘3>(0.5)’, ‘5>(0.5)’, ‘1(0.75)’, ‘5(0.25)’, ‘3(0.5)’, ‘5(0.5)’, ‘1(0.75)’, ‘5(0.25)’, ‘3(0.5)’, ‘5(0.5)’, ‘1(0.75)’, ‘6(0.25)’, ‘4(0.5)’, ‘6(0.5)’, ‘1(0.75)’, ‘5(0.25)’, ‘3(0.5)’, ‘5(0.5)’, ‘1(0.75)’, ‘6(0.25)’, ‘4(0.5)’, ‘6(0.5)’, ‘1(0.75)’, ‘5(0.25)’, ‘3(0.5)’, ‘5(0.5)’, ‘7>(0.75)’, ‘5(0.25)’, ‘2(0.5)’, ‘5(0.5)’, ‘1(0.75)’, ‘5(0.25)’, ‘3(0.5)’, ‘5(0.5)’, ‘1(0.75)’, ‘3(0.25)’, ‘5(0.5)’, ‘1<(0.5)’, ‘1(0.75)’, ‘4(0.25)’, ‘6(0.5)’, ‘1<(0.5)’, ‘1(0.75)’, ‘3(0.25)’, ‘5(0.5)’, ‘1<(0.5)’, ‘5>(0.75)’, ‘7>(0.25)’, ‘2(0.5)’, ‘5(0.5)’, ‘1(0.75)’, ‘3(0.25)’, ‘5(0.5)’, ‘1<(0.5)’, ‘1(0.75)’, ‘4(0.25)’, ‘6(0.5)’, ‘1<(0.5)’, ‘1(0.75)’, ‘3(0.25)’, ‘5(0.5)’, ‘1<(0.5)’, ‘5>(0.75)’, ‘7>(0.25)’, ‘2(0.5)’, ‘5(0.5)’, ‘1(0.75)’, ‘5(0.25)’, ‘3(0.5)’, ‘5(0.5)’, ‘1(0.75)’, ‘5(0.25)’, ‘3(0.5)’, ‘5(0.5)’, ‘1(0.75)’, ‘6(0.25)’, ‘4(0.5)’, ‘6(0.5)’, ‘1(0.75)’, ‘5(0.25)’, ‘3(0.5)’, ‘5(0.5)’, ‘1(0.75)’, ‘6(0.25)’, ‘4(0.5)’, ‘6(0.5)’, ‘1(0.75)’, ‘5(0.25)’, ‘3(0.5)’, ‘5(0.5)’, ‘7>(0.75)’, ‘5(0.25)’, ‘2(0.5)’, ‘5(0.5)’, ‘1>(2)’] }额,是不是很复杂,很臃肿。。。它以简谱为载体,通过特殊符号来标记音高和时长,从而产生mainTrack和backingTrack两个音轨,然后同步播放即可。这种实现虽然简单,但有很多致命缺点:不兼容通用的计算机乐谱格式,如musicxml不能完全表示音乐的所有维度,比如很多钢琴谱不止有两个音轨过于抽象和复杂,不实用,很难制作这种识别格式音乐专业人士: what are you 弄啥嘞?所以笔者转向另一种实现思路,解析musicxml,但奈何这个过程耗时耗力,目前只完成了一半,部分细节还没有完全解析正确,如果读者有好的想法,可以在评论区留言探讨。欢迎贡献协作贡献代码,直接PR贡献首页展示的随机歌词: https://github.com/WarpPrism/…贡献快速入门的弹奏方法: https://github.com/WarpPrism/…没想到短时间内能有这么多star(`・・´),吓得晚上下班回去又继续码代码。。。不过此项目仍不完善,还在不断更新中,特别是入门弹奏谱子比较少,目前只有:小星星新年好因为爱情隐形的翅膀蒲公英的约定纸短情长同桌的你晴天千与千寻主题曲明天你好青花瓷…都是笔者一个一个手打出来的T_T,能力有限,会的就这么多,所以是时候见证社区的力量了。FORK时,请遵循GPL开源协议。最后最后再贴一下体验地址: http://crystalworld.gitee.io/…欢迎体验,分享。解析musicxml的过程仍在进行中,如果某一天成功了,那么示例演奏里面就会加入海量的歌曲,以供学习,如果失败了,额,那就是因为生活阻挡了我奋进的脚步。。。原创不易,转载分享时请注明出处~ ...

April 8, 2019 · 3 min · jiezi

Git 常用命令

配置用户git config –global user.name “姓名"git config –global user.email “邮箱"克隆仓库git clone <url>新建分支基于mastergit checkout -b new-branch-name -t master或git checkout -b new-branch-name origin/master拉取远程分支,创建切换到本地分支git checkout -b 本地分支 origin/远程分支 (采用此种方法建立的本地分支会和远程分支建立映射关系)建立两个分支的映射(将当前分支映射到远程的指定分支,注意切换到当前分支)git branch -u origin/远程分支切换分支git checkout branch-name查看本地状态git status查看本地修改内容git diff比较本地文件和远程文件的区别git diff origin/master 文件路径在本地提交代码某一文件git commit -m ‘提交信息’ filename.txt在本地提交所有文件git commit -m ‘提交信息’ -a更新分支到githubgit push origin new-branch-name删除本地已被合并的分支git fetch -p origin读取远程仓库修改git fetch远程更新后将改动纳入本地分支git rebase remote-branch删除远程分支git branch -r -d origin/branch-name或git push origin :branch-name拉取最新代码:git pull <remote> <branch>或git pull –rebase <remote> <branch>强制更新单个文件:1) git fetch2) git checkout origin/master – path/to/file放弃本地修改,强制更新1) git fetch –all2) git reset –hard origin/masterfetch使用:git fetch origin master:temp (采用此种方法建立的本地分支不会和远程分支建立映射关系)比较本地的仓库和远程参考的区别$ git diff temp合并temp分支到master分支$ git merge temp如果不想要temp分支了,可以删除此分支$ git branch -d temp ...

April 8, 2019 · 1 min · jiezi

D2 日报 2019年4月8日

???? 新闻➡️ 多款国产浏览器封锁996.ICU,中国程序员惹谁了? www.infoq.cn➡️ 拒绝996,中国程序员的呼声传到了国外 www.infoq.cn➡️ JS 引擎 V8 发布 v7.4 性能再次大幅提高 - Google Chrome 谷歌浏览器 www.cnbeta.com???? 开源项目➡️ zhihu/griffith watch 26 star 1274 fork 72 知乎开源的视频播放器 github.com➡️ muan/emoji-minesweeper emoji 网页扫雷 github.com➡️ emojicode/emojicode 非中文 watch 49 star 1671 fork 107 emoji 编程 github.com➡️ cnlh/nps watch 82 star 2682 fork 346 一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持tcp、udp流量转发,可支持任何tcp、udp上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析等等……),此外还支持内网http代理、内网socks5代理、p2p等,并带有功能强大的web管理端 github.com➡️ Dawninest/jikeCalendar-macOS-dock watch 2 star 20 fork 0 即刻黄历 macOS dock 栏工具 github.com➡️ ericandrewlewis/emoji-mosaic watch 14 star 395 fork 52 将图片转为用 emoji 填充的新图 github.com➡️ WarpPrism/AutoPiano watch 16 star 905 fork 74 自由钢琴 AutoPiano github.com➡️ MariaLetta/free-gophers-pack 非中文 watch 17 star 669 fork 33 一整套 Go 语言插画 github.com➡️ ethantw/Han watch 84 star 1709 fork 116 「漢字標準格式」印刷品般的漢字排版框架 github.com➡️ codex-team/editor.js watch 69 star 4304 fork 131 非常棒的 Block Editor,外观漂亮功能强大 github.com➡️ Remix-Design/remixicon watch 5 star 207 fork 6 一套面向设计师和开发者的开源图标库 github.com➡️ mengdu/m-message watch 2 star 29 fork 3 Vue Messgae 提示插件 github.com➡️ zhaoolee/StarsAndClown watch 2 star 12 fork 0 Github 星聚弃疗榜 github.com➡️ GitHub - DimaLiLongJi/InDiv fork 2 An angular like web mvvm library.一个类 angular Web mvvm库。https://dimalilongji.github.i… github.com???? 分享➡️ GitHub Games 把 GitHub 上一些有趣的 HTML 小游戏进行汉化,然后放到上面供人玩耍 likexia.gitee.io➡️ rrweb:打开 web 页面录制与回放的黑盒子 zhuanlan.zhihu.com➡️ Markdown 的 100 个骚操作(更新 100 年) sspai.com➡️ React下原生G2、Echarts、D3对比 juejin.im➡️ 装了啥 2019 版 juejin.im???? 教程➡️ asyncawait偏好处理方式 juejin.im???? 网站➡️ Animated GIF editor and GIF maker 非中文 在线动图压缩和制作工具 ezgif.com➡️ EasyMoza.com 制作蒙太奇效果的图片(小图拼大图) www.easymoza.com➡️ ColouriseSG 黑白图片着色 colourise.sg➡️ 我爱搜盘 搜索百度网盘资源,查找提取密码 www.52sopan.com➡️ Pretty Awesome Lists 非中文 专门收集 Awesome 项目的项目 www.prettyawesomelists.com➡️ Pornhub Style Icon Generator 非中文 Pornhub 风格图标生成器 vincent-yao27.github.io➡️ Photopea 非中文 免费的在线版 PS,还支持编辑 sketch 文件 www.photopea.com➡️ 网易云音乐 | Moe Tools 可以下载网易云音乐中的音乐的网站!!! www.boxmoe.tools???? 工具➡️ Blend2D 非中文 2D 矢量图形引擎 blend2d.com➡️ Lark 今日头条出品的企业级IM www.larksuite.com➡️ 萌工具箱 一个现代化多功能工具箱 www.boxmoe.tools???? 设计➡️ 叮当设计 一个完全免费的优秀设计素材资源下载网站 www.dingdangsheji.com➡️ Pathlove 一个小型的个人项目,在此可以下载免费的 svg 图标 pathlove.com☕️ 更优雅地阅读阅读我们精心排版之后的页面 《D2 日报 2019年4月8日》???? 往期回顾您可以访问下面的链接浏览往期内容,或者模糊检索。https://daily.fairyever.com???? 提交分享你的发现和创造 投稿/提交方式???? 如何获取日报➡️ 官方官方网站 ????RSS ????Github | Releases➡️ 微信公众号扫描下方二维码关注“今日前端”公众号,看日报不迷路!????公众号文章版本经过特殊优化,以提高微信环境内的阅读体验。➡️ 社区主页掘金 ????即刻 ????Segmentfault简书开源中国CSDN ...

April 8, 2019 · 2 min · jiezi

gitHub中的readme.md

标题标题表示法:分为六个等级,显示的文本大小依次减小。不同等级之间是以井号 # 的个数来标识的。一级标题有一个 #,二级标题有两个# ,以此类推。注意:#与标题名中间的空格# 一级标题## 二级标题### 三级标题#### 四级标题换行在你想换行的地方加一个&lt;br> 就行.强调强调 (示例:斜体)强调 (示例:斜体)加重强调 (示例:粗体)加重强调 (示例:粗体)特别强调 (示例:粗斜体)特别强调 (示例:粗斜体)代码圆点符圆点符(注意中间有一个空格)* 第一条缩进>数据结构 >>树 >>>二叉树 >>>>平衡二叉树 >>>>>满二叉树 部分文字的高亮链接举个例子一目了然:文字超链接:百度图片超链接:分割线——————— 上面是分割线

April 7, 2019 · 1 min · jiezi

gitbook 入门教程之实用插件(持续更新)

disqus 评论插件discus 是一款集成评论的插件,可以为静态网站添加动态评论,让你的网站动起来!遗憾的是,discus 插件只有 FQ 才能正常使用,暂时没找到其他较好的替代方案.注册 disqus.com 账号gitbook 集成 disqus 插件中最重要的配置项就是注册 disqus.com 网站唯一标识.注册并绑定域名如果没有注册账号请先注册,否则直接登录,当然也支持第三方账号登录(我使用的是谷歌账号).人机验证时,选出符合条件的全部图形,直到没有新的图形为止,这一点和国内的静态图片验证是不同的!选择安装 disqus 插件(I want to install Disqus on my site ),接下来会绑定集成网站的域名.接下来设置网站的相关信息,其中网站名称(snodreams1006)是唯一标示,接下来集成到 gitbook 用的就是这个简短名称,而分类和语言按照实际情况选择即可.选择服务类型disqus 网站提供的服务类型,有基础班(basic),加强版(plus),专业版(pro)和免费版(free).每个版本计划有不同的收费标准以及相应的服务,可以根据实际情况选择适合自己的服务类型.接下来以免费版为例进行有关演示安装并配置 disqus 到网站估计是这些网站提供了默认的集成方式,这里并没看到 gitbook 相关的网站,因此选择最后一个自定义网站.填写网站的基本信息,其中网站缩写名称仍然是 snowdreams1006,网址填写 https://snowdreams1006.github.io/ ,至于其他信息根据实际情况填写即可.至此 disqus.com 网站配置完成,接下来我们配置 gitbook 集成 disqus 插件.安装并配置 disqus 插件上一步我们已经获取到唯一的标识: snowdreams1006 ,接下来可以继续配置 disqus 插件了.链接地址: https://plugins.gitbook.com/p…激活插件配置在 book.json 中配置 disqus 插件,根据实际情况修改成自己的缩写名称(shortName).示例:{ “plugins”: [“disqus”], “pluginsConfig”: { “disqus”: { “shortName”: “snowdreams1006” } }}安装 disqus 插件示例:$ gitbook install测试 disqus 插件示例:$ gitbook serve正常情况下(FQ),disqus 插件已经成功集成到 gitbook 网站了,因此推送到实际服务器上时看到的效果是这样的.如果你不具备条件(FQ),那么你看到的仍然是这样的.edit-link 编辑链接插件如果希望将网页源码暴露出去并接受公众的监督校准的话,使用edit-link插件可以直接链接到源码文件.链接地址: https://plugins.gitbook.com/p…激活插件配置在 book.json 中配置 edit-link 插件,详细说明请参考 edit-link 插件.示例:{ “plugins”: [“edit-link”], “pluginsConfig”: { “edit-link”: { “base”: “https://github.com/snowdreams1006/snowdreams1006.github.io/blob/master", “label”: “编辑本页” } }}安装 edit-link 插件示例:$ gitbook install测试 edit-link 插件如果不能正常跳转到源码文件,多次试验后重新更改 edit-link.base 节点内容,重新 gitbook serve 即可正常跳转源码文件.示例:$ gitbook servegithub 插件添加 github 图标链接,方便直接跳转到 github 指定仓库.链接地址: https://plugins.gitbook.com/p…激活插件配置在 book.json 中配置 github 插件,详细说明请参考 github 插件.示例:{ “plugins”: [“github”], “pluginsConfig”: { “github”: { “url”: “https://github.com/snowdreams1006/snowdreams1006.github.io" } }}安装 github 插件示例:$ gitbook install测试 github 插件示例:$ gitbook servesearch-plus 中文搜索插件splitter 分割线插件sharing-plus 增强分享插件donate 捐赠插件copy-code-button 复制代码插件 ...

April 6, 2019 · 1 min · jiezi

gitbook 入门教程之使用 gitbook.com 在线开发电子书

gitbook 官网是官方提供的图书托管的在线平台,分为新版官网(需要FQ) https://www.gitbook.com/ 和旧版官网(无需FQ) https://legacy.gitbook.com 两个网站.目前均正常提供服务,但令人遗憾的是,两个网站的信息相互独立,而且现在注册的账号默认只能在新版官网中使用,而新版官网的访问速度简直比 github 还要慢,所以国内用户在线访问你的电子书真的需要点技术手段了!本文主要介绍 www.gitbook.com 官网的基本使用,而 legacy.gitbook.com 网站我就算是想介绍也没有账号测试啊.“巧妇难为无米之炊”,明明你就在那里,可我却什么也做不了.先大概说一下 gitbook.com 网站的一些个人总结吧.gitbook.com 提供收费和免费服务,有点像早期的 github ,免费账号只能创建一个私有的命名空间,其他命名空间只能是公开的,这里的命名空间可以理解为一本书.这一点是不是有点像早期的 github.com?免费账号无法创建私有仓库,只能是公开仓库.(现在 github.com 已被微软收购,目前可以创建无限量的私有仓库了!)再说 gitbook 的账号问题,像 github 一样提供用户名和邮箱登录方式,他们的用户名都可以作为二级域名,比如我的用户名是snowdreams1006,那么我的 gitbook 第一本电子书网址就是 https://snowdreams1006.gitbook.io/index/ ,再看一下我的 github 个人网址 https://snowdreams1006.github.io/ ,这两个是不是很类似?!如果不仔细看的话,八成你会觉得一样,一个是gitbook.io,另一个是github.io.所以我严重怀疑他俩是不是有着不为人知的私密关系,太多的相似性,鼓励分享,限制私有等等特点.无图无真相,趁着这次教程顺便将 github 个人网站项目同步到 gitbook 电子书项目了,这样的好处是本地只需要推送到 github ,自动更新 github.io 网站(利用的是github 静态网站托管服务) ,然后再自动同步到 gitbook.io 网站.是不是很神奇,一份源码,两个官网!gitbook : https://snowdreams1006.gitbook.io/github : https://snowdreams1006.github.io/注册并登陆 gitbook.com注册信息主要包括用户名和邮箱,还有一些其他信息,没什么特殊的注意事项.访问 https://www.gitbook.com/ 需要 FQ新建命名空间(电子书)注册账后后会默认生成一个私有的命名空间,因为并不打算将私有电子书托管到 gitbook,所以接下来直接将其转变成公开电子书进行演示.个性性配置标题和图片主题颜色和页面反馈观众观众指的是当前电子书面向的受众是谁,公开的和私有的的区别以及设置是否被谷歌搜索收录.域名默认域名是 https://snowdreams1006.gitbook.io/<space>,如果需要自定义域名,请保证 dns 能够正确解析到该网站.url 设置的命名空间是 index,因此最终访问路径是 https://snowdreams1006.gitbook.io/index/整合gitbook 默认提供4种整合方式,在下孤陋寡闻只了解 github ,其余三种没接触过,暂不涉及.选择 github 进行整合登录 github 并授权选择列出公开的仓库,然后输入用户名和密码进行登录并授权.选择目标仓库授权成功后会列出当前 github 账号下全部的公开仓库,选择目标仓库并点击下一步.这里以 snowdreams1006.github.io 公开仓库为例,因为该仓库是本人官网源码项目.同步内容选择同步分支根据实际情况选择同步分支,因为我一般是直接推送到 master 分支,所以 master 分支是个人网站的维护分支,因此这一步我选择的是 master.选择同步内容选择同步内容的方式,是从 github 同步到 gitbook,还是从 gitbook 同步到 github,因为我的项目已托管到 github ,所以初次同步内容选择的是 github –> gitbook.显示 github 按钮生成的电子书网站是否显示 github 按钮,作用是点击该按钮会跳转到关联的github 仓库上.此时心里在想,万一点进 github ,随手就是一个 star 呢?哈哈!等待内容导入根据目标仓库的大小不同,导入内容是的时长自然也不一样,耐心等待…上线导入完成,电子书终于正式上线了!现在赶紧分享一下好消息吧,访问 https://<username>.gitbook.io/<space> 在线阅读!小结本文以如何集成 github 为例,演示了 gitbook.com 发布电子书的基本流程,由于 gitbook 电子书内容来自于 github 项目,因此我们只要更新 github 仓库,我们的 gitbook 电子书网站自然也就相应更新了!gitbook 是 markdown 和 github 的完美结合体,借助 gitbook.com 官网我们很容易发布并托管电子书.美中不足的是,国内无法正常访问 gitbook.com ,因此并不是很推荐将电子书发布到 gitbook.com 网站.现在国内也有类似的产品,有一种产品叫做 看云,还不错!后续还会介绍 gitbook 如何结合 github 发布个人网站,欢迎继续关注 gitbook 系列教程!如何打造免费的个人官网,想了解 https://snowdreams1006.github.io/ 背后的故事吗? ...

April 5, 2019 · 1 min · jiezi

打通前后端逻辑,客户端Flutter代码一天上线

一、前沿 随着闲鱼的业务快速增长,运营类的需求也越来越多,其中不乏有很多界面修改或运营坑位的需求。闲鱼的版本现在是每2周一个版本,如何快速迭代产品,跳过窗口期来满足这些需求?另外,闲鱼客户端的包体也变的很大,企业包的大小,iOS已经到了94.3M,Android也到了53.5M。Android的包体大小,相比2016年,已经增长了近1倍,怎么能将包体大小降下来?首先想到的是如何动态化的解决此类问题。 对于原生的能力的动态化,Android平台各公司都有很完善的动态化方案,甚至Google还提供了Android App Bundles让开发者们更好地支持动态化。由于Apple官方担忧动态化的风险,因此并不太支持动态化。因此动态化能力就会考虑跟Web结合,从一开始基于 WebView 的 Hybrid 方案 PhoneGap、Titanium,到现在与原生相结合的 React Native 、Weex。 但Native和JavaScript Context之间的通讯,频繁的交互就成了程序的性能瓶颈。于此同时随着闲鱼Flutter技术的推广,已经有10多个页面用Flutter实现,上面提到的几种方式都不适合Flutter场景,如何解决这个问题Flutter的动态化的问题?二、动态方案我们最初调研了Google的动态化方案CodePush。2.1 CodePush CodePush是谷歌官方推出的动态化方案,目前只有在Android上面实现了。Dart VM在执行的时候,加载isolate_snapshot_data 和isolate_snapshot_instr 2个文件,通过动态更改这些文件,就达到动态更新的目的。官方的Flutter源码当中,已经有相关的提交来做动态更新的内容,具体内容可以参考 ResourceExtractor.java。 根据官方给出的Guide,我们这边也做了相关的测试,patch的包体大小会很大(939kb)。为了降低包体大小,还可以通过增量的修改snapshot文件的方式来更新。通过bsdiff生成的snapshot的差异文件,2个文件分别可以缩小到48kb和870kb。 目前看来,CodePush还不能做到很好的工程化。而且如何管理patch文件,需要制定baseline和patch文件的规则。2.2 动态模板 动态模板,就是通过定义一套DSL,在端侧解析动态的创建View来实现动态化,比如LuaViewSDK、Tangram-iOS和Tangram-Android。这些方案都是创建的Native的View,如果想在Flutter里面实现,需要创建Texture来桥接;Native端渲染完成之后,再将纹理贴在Flutter的容器里面,实现成本很高,性能也有待商榷,不适合闲鱼的场景。 所以我们提出了闲鱼自己的Flutter动态化方案,前面已经有同事介绍过方案的原理:《做了2个多月的设计和编码,我梳理了Flutter动态化的方案对比及最佳实现》,下面看下具体的实现细节。三、模板编译自定义一套DSL,维护成本较高,怎么能不自定义DSL来实现模板下发?闲鱼的方案就是直接将Dart文件转化成模板,这样模板文件也可以快速沉淀到端侧。3.1 模板规范 先来看下一个完整的模板文件,以新版我的页面为例,这个是一个列表结构,每个区块都是一个独立的Widget,现在我们期望将“卖在闲鱼”这个区块动态渲染,对这个区块拆分之后,需要3个子控件:头部、菜单栏、提示栏;因为这3部分界面有些逻辑处理,所以先把他们的逻辑内置。内置的子控件分别是MenuTitleWidget、MenuItemWidget和HintItemWidget,编写的模板如下:@overrideWidget build(BuildContext context) { return new Container( child: new Column( children: <Widget>[ new MenuTitleWidget(data), // 头部 new Column( // 菜单栏 children: <Widget>[ new Row( children: <Widget>[ new MenuItemWidget(data.menus[0]), new MenuItemWidget(data.menus[1]), new MenuItemWidget(data.menus[2]), ], ) ], ), new Container( // 提示栏 child: new HintItemWidget(data.hints[0])), ], ), );}中间省略了样式描述,可以看到写模板文件就跟普通的widget写法一样,但是有几点要注意:每个Widget都需要用new或const来修饰数据访问以data开头,数组形式以[]访问,字典形式以.访问 模板写好之后,就要考虑怎么在端上渲染,早期版本是直接在端侧解析文件,但是考虑到性能和稳定性,还是放在前期先编译好,然后下发到端侧。3.2 编译流程 编译模板就要用到Dart的Analyzer库,通过parseCompilationUnit函数直接将Dart源码解析成为以CompilationUnit为Root节点的AST树中,它包含了Dart源文件的语法和语义信息。接下来的目标就是将CompilationUnit转换成为一个JSON格式。 上面的模板解析出来build函数孩子节点是ReturnStatementImpl,它又包含了一个子节点InstanceCreationExpressionImpl,对应模板里面的new Container(…),它的孩子节点中,我们最关心的就是ConstructorNameImpl和ArgumentListImpl节点。ConstructorNameImpl标识创建节点的名称,ArgumentListImpl标识创建参数,参数包含了参数列表和变量参数。定义如下结构体,来存储这些信息:class ConstructorNode { // 创建节点的名称 String constructorName; // 参数列表 List<dynamic> argumentsList = <dynamic>[]; // 变量参数 Map<String, dynamic> arguments = <String, dynamic>{};}递归遍历整棵树,就可以得到一个ConstructorNode树,以下代码是解析单个Node的参数:ArgumentList argumentList = astNode;for (Expression exp in argumentList.arguments) { if (exp is NamedExpression) { NamedExpression namedExp = exp; final String name = ASTUtils.getNodeString(namedExp.name); if (name == ‘children’) { continue; } /// 是函数 if (namedExp.expression is FunctionExpression) { currentNode.arguments[name] = FunctionExpressionParser.parse(namedExp.expression); } else { /// 不是函数 currentNode.arguments[name] = ASTUtils.getNodeString(namedExp.expression); } } else if (exp is PropertyAccess) { PropertyAccess propertyAccess = exp; final String name = ASTUtils.getNodeString(propertyAccess); currentNode.argumentsList.add(name); } else if (exp is StringInterpolation) { StringInterpolation stringInterpolation = exp; final String name = ASTUtils.getNodeString(stringInterpolation); currentNode.argumentsList.add(name); } else if (exp is IntegerLiteral) { final IntegerLiteral integerLiteral = exp; currentNode.argumentsList.add(integerLiteral.value); } else { final String name = ASTUtils.getNodeString(exp); currentNode.argumentsList.add(name); }}端侧拿到这个ConstructorNode节点树之后,就可以根据Widget的名称和参数,来生成一棵Widget树。四、渲染引擎端侧拿到编译好的模板JSON后,就是解析模板并创建Widget。先看下,整个工程的框架和工作流:工作流程:开发人员编写dart文件,编译上传到CDN端侧拿到模板列表,并在端侧存库业务方直接下发对应的模板id和模板数据Flutter侧再通过桥接获取到模板,并创建Widget树对于Native测,主要负责模板的管理,通过桥接输出到Flutter侧。4.1 模板获取模板获取分为2部分,Native部分和Flutter部分;Native主要负责模板的管理,包括下载、降级、缓存等。程序启动的时候,会先获取模板列表,业务方需要自己实现,Native层获取到模板列表会先存储在本地数据库中。Flutter侧业务代码用到模板的时候,再通过桥接获取模板信息,就是我们前面提到的JSON格式的信息,Flutter也会有缓存,已减少Flutter和Native的交互。4.2 Widget创建Flutter侧当拿到JSON格式的,先解析出ConstructorNode树,然后递归创建Widget。创建每个Widget的过程,就是解析节点中的argumentsList和arguments 并做数据绑定。例如,创建HintItemWidget需要传入提示的数据内容,new HintItemWidget(data.hints[0]),在解析argumentsList时,会通过key-path的方式从原始数据中解析出特定的值。解析出来的值都会存储在WidgetCreateParam里面,当递归遍历每个创建节点,每个widget都可以从WidgetCreateParam里面解析出需要的参数。/// 构建widget用的参数class WidgetCreateParam { String constructorName; /// 构建的名称 dynamic context; /// 构建的上下文 Map<String, dynamic> arguments = <String, dynamic>{}; /// 字典参数 List<dynamic> argumentsList = <dynamic>[]; /// 列表参数 dynamic data; /// 原始数据} 通过以上的逻辑,就可以将ConstructorNode树转换为一棵Widget树,再交给Flutter Framework去渲染。至此,我们已经能将模板解析出来,并渲染到界面上,交互事件应该怎么处理?4.3 事件处理在写交互的时候,一般都会通过GestureDector、InkWell等来处理点击事件。交互事件怎么做动态化? 以InkWell组件为例,定义它的onTap函数为openURL(data.hints[0].href, data.hints[0].params)。在创建InkWell时,会以OpenURL作为事件ID,查找对应的处理函数,当用户点击的时候,会解析出对应的参数列表并传递过去,代码如下:…final List<dynamic> tList = <dynamic>[];// 解析出参数列表exp.argumentsList.forEach((dynamic arg) { if (arg is String) { final dynamic value = valueFromPath(arg, param.data); if (value != null) { tList.add(value); } else { tList.add(arg); } } else { tList.add(arg); }});// 找到对应的处理函数final dynamic handler = TeslaEventManager.sharedInstance().eventHandler(exp.actionName);if (handler != null) { handler(tList);}…五、 效果新版我的页面添加了动态化渲染能力之后,如果有需求新添加一种组件类型,就可以直接编译发布模板,服务端下发新的数据内容,就可以渲染出来了;动态化能力有了,大家会关心渲染性能怎么样。5.1 帧率在加了动态加载逻辑之后,已经开放了2个动态卡片,下图是新版本我的页面近半个月的的帧率数据:从上图可以看到,帧率并没有降低,基本保持在55-60帧左右,后续可以多添加动态的卡片,观察下效果。注:因为我的页面会有本地的一些业务判断,从其他页面回到我的tab,都会刷新界面,所以帧率会有损耗。 从实现上分析,因为每个卡片,都需要遍历ConstructorNode树来创建,而且每个构建都需要解析出里面的参数,这块可以做一些优化,比如缓存相同的Widget,只需要映射出数据内容并做数据绑定。5.2 失败率现在监控了渲染的逻辑,如果本地没有对应的Widget创建函数,会主动抛Error。监控数据显示,渲染的流程中,还没有异常的情况,后续还需要对桥接层和native层加错误埋点。六、展望 基于Flutter动态模板,之前需要走发版的Flutter需求,都可以来动态化更改。而且以上逻辑都是基于Flutter原生的体系,学习和维护成本都很低,动态的代码也可以快速的沉淀到端侧。 另外,闲鱼正在研究UI2Code的黑科技,不了解的老铁,可以参考闲鱼大神的这篇文章《重磅系列文章!UI2CODE智能生成Flutter代码——整体设计篇》。可以设想下,如果有个需求,需要动态的显示一个组件,UED出了视觉稿,通过UI2Code转换成Dart文件,再通过这个系统转换成动态模板,下发到端侧就可以直接渲染出来,程序员都不需要写代码了,做到自动化运营,看来以后程序员失业也不是没有可能了。 基于Flutter的Widget,还可以拓展更多个性化的组件,比如内置动画组件,就可以动态化下发动画了,更多好玩的东西等待大家来一起探索。参考文献https://github.com/flutter/flutter/issues/14330https://www.dartlang.org/https://mp.weixin.qq.com/s/4s6MaiuW4VoHr_7f0S_vuQhttps://github.com/flutter/engine本文作者:闲鱼技术-景松阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

April 4, 2019 · 2 min · jiezi

Git 入门(二)--- 常用指令和问题处理

关于Add与Commitgit add . 将所有修改提交到stage 缓存区git commit 将缓存区的更改提交到本地仓库那么,问题来了:如何取消commit,也就是撤销提交到本地仓库的操作?如何取消add,也就是撤销提交到缓存区的操作?如何取消更改,也就是说,修改了文件或者增加了文件或者删除了文件这时候怎么撤销?放弃文件修改(修改了文件,未执行 git add 命令)放弃单个文件的修改 git checkout xxx xxx是文件path放弃所有文件更改git checkout .放弃文件的增加(新建了文件、为add)放弃单个文件的新增rm xxx,其实就是cmd删除文件命令放弃所有新增的文件git clean xdf,删除所有新增的文件(不包括已经添加到缓存区的)。撤销提交到缓存区(执行了git add .命令,未commit)撤销单个文件git reset HEAD xxx,xxx是文件名撤销所有文件git reset HEAD .撤销提交到本地仓库(即取消git commit)说明,执行了git commit之后,相当于本地仓库已经更新了一个版本,就等待push了,那么要撤销commit也就是要回退版本,这种情形就是要将本地仓库回退1个版本。git reset –hard HEAD^ // –hard 是参数,^是上一版本,// 也可以用~1、~2,表示回退多少个版本–soft / –hard / –mixed 三个参数的说明:–soft:暂存区的内容和本地已提交的内容全部恢复到未暂存的状态,换言之,add和commit的内容全部都会变成未add的状态。–mixed:保留缓存区的内容,已提交的内容回到缓存区。–hard:缓存区的内容和已提交的内容都会被清空。(慎用!)关于创建分支git checkout -b xxx 创建并切换到xxx分支,其实,这是在当前分支的基础上创建xxx分支,并切换到xxx分支。也可以指定以其他分支为基础来创建:git checkout -b xxx master。涉及的问题:如果当前所在分支有未add到缓存区或者未commit的更改时是不能切换分支的,也就是说上述的创建并切换到分支是不会执行的。因此,当前所在分支要commit后才能切换分支。合并其他分支git merge xxx 将xxx分支合并到当前分支。关于删除分支删除本地分支git branch -D xxx 注意大写D删除远程的分支git push orgin -d xxx

April 4, 2019 · 1 min · jiezi

7步把本地Git仓库推送到已新建的Github仓库

你在本地已经一个项目,想使用Git进行版本管理,并推送到已新建的GitHub仓库。可参考以下步聚:# 1 进入项目目录cd /xx/xx/o2o# 2 初始化本地git仓库git init# 3 在你的项目中设置你在GitHub新建的公开仓库,并命名为 origingit remote add origin https://github.com/Guoye/o2o.git# 4 拉取Github仓库上master主分支上的文件git pull origin master##########代码提交并推送################## 5 把所有的代码加入缓存区 除.gitignore排除外git add *# 6 提交代码,并附上消息:“init"git commit -m “init”# 7 推送代码到远程仓库 origin 的master主分支上git push –set-upstream origin master# 完成

April 4, 2019 · 1 min · jiezi

三分钟搭建个人博客(Hexo + Next + github)详细教程

每个程序员必不可少的就是博客网站了,一开始我们并不知道可以搭建属于自己的个人博客网站,通常会在CSDN、博客园等别人搭建的博客网站写博客,当你写久了以后会感觉很 low, 一些文章需要审核通过才能发布。索性我们还不如自己搭建一个个人博客,个人博客的设计美化和内容都按照自己喜欢的要求来,然后在阿里云买一个高大上的域名,岂不是很装逼?尽管你没有学过网页 web 开发,但是通过这篇小鹿详细教程可以亲自搭建起属于自己的个人博客。小鹿的博客网址:小鹿的博客建站前的准备建站之前我们先要做好准备工作,将相关的工具准备好。安装 Node.jsNode.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。安装网址:https://nodejs.org/zh-cn/验证是否安装成功:打开 cmd 命令行(win+r 输入 cmd 回车)执行 :node -vnpm -v安装成功之后显示版本号:安装 Git通常使用 github 的对 git 并不陌生,Git(读音为/gt/。)是一个开源的分布式版本控制系统,可以有效、高速的处理从很小到非常大的项目版本管理。 [1] Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。安装网址:https://www.git-scm.com/download/win验证是否安装成功:打开cmd命令行(win+r 输入cmd回车)执行 :git –version安装成功之后显示版本号:安装 HexoHexo 是一个快速、简洁且高效的博客框架。了解更多关于 Hexo 请查看官方网站:Hexo安装 hexo 框架下面一起来看看怎么安装 Hexo 框架?首先选择一个文件夹,这个文件夹主要存放关于你博客的配置文件以及以后要写的的文章,在该文件夹的根目录运行之前下好的 git-bash.exe 。输入命令开始安装:$ npm install -g hexo-cli这里安装的是 Hexo 最新版本,如果想安装以前的的版本请运行命令 $ npm install -g hexo 以上步骤不出问题的话就已经在本地机器上搭建起了 Hexo 环境。下面介绍 Hexo 的具体使用方法。初始化Hexo创建hexo工程$ hexo init blog创建一个文件夹blog(blog 为文件夹的名字,可改成自己想要的名字),使用 Hexo 命令初始化 blog 为 hexo 工程目录。新建POST $ cd blog$ hexo new “HelloWorld”进入初始化后的 blog 文件夹,创建名为HelloWorld的文件,此时会在 /blog/sources/_post/ 目录下生成 HelloWorld.md 文件。生成静态文件$ hexo generate使用 Hexo 引擎将 Markdown 格式的文件解析成可以使用浏览器查看的 HTML 文件,HTML 文件存储在 blog/public 目录下。运行hexo服务器$ hexo server打开命令行提示的地址,一般是 http://localhost:4000/,既可以看到我们的 Hexo 网站。此时 Helloworld 文章中没有任何内容。打开 /blog/sources/_post/ 目录,使用编辑器打开其中的 HelloWorld.md并在其中添加 markdown 格式的内容保存,然后重新运行以下命令:$ hexo generate$ hexo server命令的含义:hexo generate 生成静态文件, hexo server 启动服务器。默认情况下,访问网址为: http://localhost:4000/。 如果重新改变端口号请详细查看官网文档,这里不多介绍。注意:如果在 HelloWorld.md文件中有中文,在网页进行浏览可能出现乱码,解决方式通过编辑器打开 HelloWorld.md 文件把编码方式改成 utf-8 就可以了。安装主题Hexo 提供了默认主题 landscape,主题的位置在 blog ->themes 文件夹下。主题根据自己喜好可以在网上找到,通过 Git 进行相应的下载。下面小鹿贴出几个主题可以进行相应的下载,喜欢哪一个可以进行配置到自己的个人博客了。主题一:hexo-theme-next(小鹿用的主题是这一个,后期是自己改进美化的)主题二:Casper主题三:daleanthony主题四:hexo-theme-yilia主题五:jacman主题六:hexo-theme-apollo小鹿给大家找了一个主题链接可以选择自己喜欢的主题:更多主题配置主题打开 git-bash 切换到 blog -> themes 目录下,如果在目录 blog ->themes 右键选择启动 git-bash 就不用切换了。如果在桌面直接启动 git-bash ,可通过下边命令切换到 blog ->themes 目录下。$ cd /blog/themes选好一个主题,复制主题的 github 地址,通过 git 命令进行下载。(例:https://github.com/iissnan/hexo-theme-next 为一个主题的 github 地址)git clone https://github.com/iissnan/hexo-theme-next下载完之后我将文件夹改成 next了(也可以不改,我为了名字简洁点)。然后在修改 /blog/config.yml 文件,将其中的 theme 改成 next。(这个是改变主题的地方,如果你用的是其他的主题,将这个 next 改成你下载下来的主题的文件夹的名称)重新运行以下命令,查看更换主题后的效果 :$ hexo generate$ hexo server申请 Github 免费静态内容空间注册 Github 账号我们去 Github 的官网进行账号注册 ,注册完成之后我们根据官方文档进行配置 ,然后我们使用自己的账户创建一个 Repository (仓库)。点击网站右上角的 + 号,选择 New Repository( 注意:创建仓库的名字要你的注册的用户名一致。其他默认,确定创建)。之后你的静态内容空间就已经创建好了,在浏览器输入你的 your username(用户名).github.io 就可以访问了。将 Hexo 上传 Github 上。步骤一:安装 deployer-git (安装部署工具,方便以后更新)$ npm install hexo-deployer-git –save步骤二:在 /blog/_config.yml 中修改 deploy 属性(注意“:”之后有空格 ) 否则配置失败。deploy: type: git repository: https://github.com/luxiangqiang/luxiangqiang.github.io.git branch: master将上方的 Repository 换成你申请的 Git 仓库地址 使用 https 的方式部署每次提交到 Github 都要输入用户名和密码,如果嫌麻烦请使用 SSH 的方式,百度/谷歌自行搜索。步骤三:初始化本地仓库。git init步骤四:连接远程仓库 ( 如果是第一次使用 git,在使用 git 的时候会提示输入用户名和密码,用户名是自己的注册邮箱。)git remote add origin https://github.com/luxiangqiang/luxiangqiang.github.io.git步骤五:发布 hexo 到 github page//等于一次性执行了,清空、刷新、部署三个命令hexo clean && hexo g && hexo d步骤六:推送到远程仓库(github)git push origin这里建议创建一个新的分支 hexo,用于管理 hexo 文件。提交的的时候只提交 hexo 网站 html、css 等源文件。 创建并切换到新建分支:git checkout -b hexo将分支推送到远程仓库:git push origin hexo记得提交以后去 github 上把 hexo 分支设置默认,以后写文章等都要部署。 文章在 hexo 目录下的 source _posts 文件夹中,是 md 格式,也就是 Markdown 格式。 ...

April 4, 2019 · 2 min · jiezi

程序员的996简史!我们是怎么一步步陷入996工作制的

最近996.ICU 这个库在github.com上迅速火爆起来,成为了这两周程序员圈最热的话题。什么是996.icu?原文引用: The name996.ICUrefers to”Work by ‘996’, sick in ICU”, an ironic saying among Chinese programmers, which means that by following the “996” work schedule, you are risking yourself getting into the ICU (Intensive Care Unit). 译:命名位 996.ICU 是指 “工作’996’,生病ICU”,这是中国程序员的讽刺说法,这意味着按照早上9点到晚上9点,一周6天的时间表工作,你就有被送进ICU(特护病房)的风险这是仓库创建者对国内程序员职场996工作制发起的抗议。我从2002年自学编程,2005年开始进入职业化软件开发工作直到现在,本来以为996.icu只是又一次的程序员搞怪吐槽,但没想到这次得到了如此之大的关注和同行们的共鸣,感慨万千!我的经历:创业-上班-再创业从2005年至今,我一直热爱我的编程工作,其间,我分别在教育部门、政府下属单位、私人企业的软件开发团队工作过,中途还和朋友一起创业,虽然不能比肩行业顶级程序员,但是也得到了身边程序员圈的认可。另外,由于入行稍早,所在城市也不是一线大城市,所以在职业经历里除了开发工作外,其余时间都是担任团队负责人的职责,这让我有机会接触到HR、企业管理方面人,同时也有时间学习到开发之外的知识在2005-2010期间,程序员圈子的薪酬并不算很高,我大学的专业是土木工程,从我大学同学那里了解到,在2005-2010这几年,程序员的薪资和前景与路桥专业的收入是没法比的。那个时候,对于程序员的需求主要还在“企业建站”领域,Web2.0的兴起带动了一波编程学习的热潮,就连大学里的计算机也增加了额外的网页开发和制作的课程。之后的几年,电子商务迅速发展,紧跟着是新媒体的崛起带动了一波又一波的程序员需求热潮。直到前几年开始,大数据、人工智能、共享经济,资本领域的狂欢,也将程序员的职业水平带到了高潮。为什么会出现996?从跳槽到996: 资本运作总是最敏捷的资本市场总是很明锐,他们观察到了经济发展的脉搏,迅速进入,赚取利润后又迅速离开。资本是敏捷的,它带来了一个理念“天下武功,唯快不破”资本需要快,需要迅速实现产品,然后卖给嗷嗷待哺的客户。据我的了解,率先自发996的是一些创业团队,不仅为了早点拿到钱,更多是受“理想”驱使,大家快乐的工作着;之后,这样的文化和氛围被传播到了其他企业,当然也会被传播到那些并没有理想驱动的企业,然后,被固化成这个职业的特性整体薪酬:学习环境、成就感、未来的理想程序员,是一个整体薪酬很高的职业。所谓整体薪酬,是指 企业 在 员工 充分参与的基础上,建立每个员工不同的薪酬组合系统,并定期随着他们兴趣爱好和需求的变化,做出相应的变更,这是一种自主风格的 薪酬制度 ,各个雇员可以按照事业发展、工作和个人生活的协调比率,决定自己的 薪酬组合 以及组合中各种薪酬元素的比例。简单说来,整体薪酬是指工作获得的总体回报,它包含钱、兴趣、认同感、成就感、发展前景、生活协调、身体健康。职业的程序员,往往自带很高的 兴趣、认同感、成就感、发展前景,再加上金钱收入也往往在所有行业中处于中高水平,因此,程序员很容易满足这样的整体薪酬,而忽略了生活协调和身体健康.多年前,程序员是一个跳槽现象很突出的职业,在人力资源供需还算平衡的时候,当时的科技公司还是比较害怕程序员跳槽的,招聘培养是一个成本很大的事情。而在资本的助力下,企业得到了足够的资金,可以快速聘用优秀的人才,程序员们得到了高薪、股权以及可能成为下一个“盖茨”、“扎克伯格”的“可能性”,所以也更有动力去努力工作。这是一个非常甜蜜的时期,没有“输家”。直到资本撤离。插播一则笑话:“我们公司最大的特点是经常可以加班”曾经有一个科技公司的老板想挖走我的一位朋友,开出的条件是:“我们公司的工资不高,但是我们有很多加班机会。”。朋友告诉我们这个事情,大家乐了很久,听上去像段子一样的真事。老板们是认真的觉得加班是程序员的爱好吗?前景理论:厌恶损失、规避风险、舒适圈著名的心理学家丹尼尔·卡尼曼(唯一一个获得诺贝尔经济学奖的心理学家)提出的前景理论说:人在获得的时候,会选择规避风险,在失去的时候选择追求风险。在程序员圈里,规避风险和追求风险是明显两极化的规避风险,留在舒适圈。在获得较高的整体薪酬后,愿意牺牲生活协调和身体健康换取当下的稳定工作。通常在职场中接收到的“调教“讯息表达出如果向老板争取休息时间,很大可能性会降低价值竞争力,被迫更换工作或者职业。追求风险,这部分程序员对目前的所获得现状不满,他们希望得到更多的钱、兴趣、认同感、成就感、发展前景,既然上班也要牺牲生活和健康,他们选择创业。在资本快速涌入的情况下,很明显,资本能够满足程序员的整体薪酬,于是多数程序员在前几年选择了规避风险不仅程序员自己是成本,而且投入的精力是沉没成本不管这个“伟大的项目”是谁编写代码开发出来的,从“老板”的角度来看,程序员只是生产产品的成本,充分利用成本是老板们的必然想法。另一方面,程序员对工作投入的精力也是成本,而且是沉没成本,这就很容易引起沉没成本偏见:在某件事情上投入了精力或者金钱,就不太愿意放弃。我有很多朋友,一面在抱怨目前的工作状态,一面又不断的加班,除了倾向于保持现状外,最多的理由就是想做完手上的项目再考虑休息的事。风起风停,为什么现在抗议?996工作制由来已久,为什么现在才受到关注和抗议?可能是执行996的企业数量越来越多、规模越来越大,大家已经无法忍受。更有可能是在2019年资本在互联网科技行业的撤离给大家一个明确的信号。资本撤离,收入是很明显的影响到了,认同感、成就感、发展前景也有所动摇。大家开始意识到曾经用生活和健康换来的整体薪酬的价值在未来将会远远低于生活和健康的价值。怎么破:后见之明现在分析原因都是后见之明,如果不反思原因,就算时间倒流,也许还是会以相同的历史轨迹发展。事业有成与身体健康并不矛盾,但是需要作出理性的选择权衡。我们需要认真思考,在“漫长”而又“短暂”的人生中,什么是最重要的??不能被眼下的得失所左右。作为一个工作了十几年的老程序员,希望大家能够正确的看待工作、生活和健康。另外,其实996并不只存在于程序员圈,我认识的许多做销售、服务、财务的人也在经历996…

April 3, 2019 · 1 min · jiezi

Zilliqa生态构建资助计划第三批获奖名单

Han Wen发布于Zilliqa博客随着 Zilliqa 主网成功发布,我们开始将精力重新集中在建设开发者社区和培养下一代区块链人才之上。我们参与了「区块链的未来(Future of Blockchain)」这样的计划,还在近期推出了「Blockchain A-Z」这样的教育活动,同时,也参与了像 ETHDenver 和 SF Developer Week 这样以开发为核心重点的活动,希望通过这样的一系列活动,以一种更有意义的方式与社区新老成员进行互动。我们始终认为,一个区块链协议的优势在于社区不断支持和推动该协议向前发展。没有社区的帮助,我们就不会有今天的成就。为了证明这一点,我们的 Zilliqa 生态构建资助项目不仅为我们的社区成员提供了创造性的平台,更是一种支持各位将创新理念努力付诸实践的方式。我们非常感谢这些杰出的团队,他们在过去几个月里不知疲倦地工作,以确保产品能够与Zilliqa主网一起发布。尽管Zilliqa网络仍处在新生阶段,这些团队依然站出来倡导开源精神,构建每个人都可以免费使用的工具。我们知道,在这个 #BUIDLER 社区的心中,仍然燃烧着不可动摇的激情,我们对这个行业的未来和今后的道路充满乐观,并且我们努力让公链的广泛应用成为现实。无须赘言,我们很激动地向您介绍第三批 Zilliqa 生态构建资助金的获奖者!第三批获奖者项目1类别:工具和库项目名称:Moonlet wallet v2.0获奖团队:Moonlet项目简介:Moonlet v2.0 是一个不受区块链平台限制的开源加密货币钱包,它允许个人处理多个帐户,可以与 Ledger Nano S 硬件设备集成,发送/接收原生 ZIL 代币,还可以与 Zilliqa 区块链上的智能合约进行交互。Moonlet 钱包提供谷歌 Chrome 浏览器插件。Github 公共资源库:https://github.com/cryptoland…项目2类别:工具和库项目名称:xZIL Android wallet获奖人:Dan Andrei项目简介:xZIL 是一个开源安卓钱包,允许个人在其安卓设备上处理多个帐户,发送/接收原生 ZIL 代币。Github 公共资源库:https://github.com/AndreiD/xz…项目3类别:工具和库项目名称:ZILMiner获奖人:Gully Chen项目简介:ZILMiner 是一个支持 Zilliqa 工作量证明(PoW)的Ethash GPU 挖矿软件。它是 ethminer 的一个分叉,包含一些附加的特性和附加组件,这些特性和附加组件是 Zilliqa 挖矿过程所特有的。Github 公共资源库:https://github.com/DurianStal…项目4类别:Dapps项目名称:Atomic swap for Fungible tokens获奖团队:KOFO项目简介:「Atomic swap for Fungible tokens」 是一个原生安卓应用程序,它允许用户在 ERC20 可替换代币和基于 Zilliqa 的可替换代币之间进行原子交换。Github 公共资源库:https://github.com/kofoproject项目5类别:工具和库项目名称:Viewblock API获奖团队:Ashlar项目简介:Viewblock API 是一套完整的开发者友好的应用程序编程接口(API)和工具。它为希望在 Zilliqa 区块链之上构建应用程序的开发人员提供便捷、可靠和实时的API服务。网址:ViewBlock项目6类别:工具和库项目名称:Composite 智能合约编辑器获奖团队:Composite项目简介:Composite是一个集成开发环境(IDE),它支持完整的编辑-调试-部署开发周期,并提供独特的链上工具的一键更新和安装。Github 公共资源库:https://github.com/compositea…项目7类别:工具和库项目名称:LaksaJ获奖团队:FireStack-Lab项目简介:LaksaJ是一个Java 软件开发工具包(SDK),为开发人员提供了一个Web3 库。Github 公共资源库:https://github.com/FireStack-…项目8类别:工具和库项目名称:LaksaCsharp获奖团队:FireStack-Lab项目简介:LaksaCsharp 为 C# SDK,为开发人员提供了一个 Web3 库。Github 公共资源库:https://github.com/FireStack-…项目9类别:工具和库项目名称:LaksaRuby获奖团队:FireStack-Lab项目简介:LaksaRuby是一个Ruby SDK,为开发人员提供了一个 Web3 库。Github 公共资源库:https://github.com/FireStack-…生态构建资助金计划更新在我们向前迈进的同时,也希望与大家分享最近对资助金的架构所作出的一些更新。我们定义了三个领域,以更好地与开发人员和相关团队接触,指导他们在 Zilliqa 上进行建设。Zilliqa生态构建资助金新的架构系统 ·基础设施领域。该领域是为那些希望创建开源开发工具、SDK、挖矿工具包或底层应用程序(钱包/浏览器/分析工具等)的 #BUIDLER 而准备的。这条领域的目标是改进Zilliqa生态系统的基础设施,使它成为对用户和开发者更加友好的环境·创新领域。这是为那些希望在 Zilliqa 区块链上创建去中心化应用程序 dApp 的创业者们所准备的。dApp 包括但不限于用于代币化资产、委托信贷发行或发行稳定币的创新型协议。dApp 也可以是游戏、新闻内容管理或信用应用,这些应用需要一个安全但可扩容的账本来跟踪所有的变化·研究领域。该领域是为寻求与 Zilliqa Research 合作,以解决一些当今行业中最紧迫的问题的研究人员而准备的。研究主题包括但不限于密码学、共识设计、扩容性和隐私通过这个新的架构系统,我们希望能够进一步扩大资助项目的规模,将视野越过区块链行业,与更广泛的受众合作。与往常一样,请随时通过Gitter 上的ecogrant 频道向我们反馈任何意见!我们期待你的想法!现在开放接受第四期申请! ...

April 3, 2019 · 1 min · jiezi

寻找 K8s 1.14 Release 里的“蚌中之珠”

摘要: K8s 1.14 发布了,Release Note那么长,我们该从何读起?本文由张磊、心贵、临石、徙远、衷源、浔鸣等同学联合撰写。Kubernetes 1.14.0 Release 已经于3月25日正式发布。相信你也已经注意到,相比于1.13 和 1.12 版本,这次发布包含的重要变更非常多,其对应的 Release Note 的篇幅长度也创下了“新高”。面对这样一份“海量信息”的 Release Note,我们该如何从这份文档里进行高效的信息过滤和挖掘,帮助团队更精准、快速的梳理出这次发布最主要的技术脉络呢?在本篇文章中,我们将 1.14 的Release Note 按照主题进行了重新归纳和梳理,按照类别对重要变更进行了技术剖析和讨论。希望这种“分类解读”的方式,能够帮助大家更好的理解 1.14 这个发布的核心内容。Windows Node 正式生产可用随着1.14的发布,Kubernetes 对windows节点的生产级支持无疑是一个重要的里程碑。具体来说,1.14 版本针对 Windows 做了大量增强;Pod:Pod内支持readiness和liveness探针;支持进程隔离和volume共享的多容器Pod;Pod支持原生configmap和sercret;Pod支持emptyDir;支持对Pod进行资源配额等;但是像优雅删除、Termination message、Privileged Containers、HugePages、Pod驱逐策略等部分特性还未在1.14版本提供;Service:支持服务环境变量提供DNS解析;支持NodePort、ClusterIP、LoadBalancer、Headless service;暂不支持Pod的hostnetwork模式;常规 Workload controller:RS、deployment、statefulset、daemonset、job、cronjob均支持windows容器;除此之外,支持Pod和container维度的metrics、HPA、“kubectl exec”、调度抢占、resource quotas、CNI 网络支持等多种特性让windows workload更加云原生;由于windows的特殊兼容性,目前 host OS的版本必须和容器镜像OS版本一致,1.14版本支持win server 2019;未来版本中会考虑使用Hyper-V隔离机制来解决版本兼容性问题。而伴随着 Windows 容器的生态正在慢慢壮大,能够在生产级别支持 Windows 节点的容器服务开始见诸各大云厂商。阿里云容器服务(ACK)近期已经推出了 Windows Container 的支持,提供了linux/windows应用混合部署的统一管理能力。参见:Support for Windows Nodes is Graduating to Stable (#116 )本地持久化数据卷(Local PV) 正式可用长期以来,能够让 Kubernetes 直接用宿主机的本地存储设备(比如:本地 SSD 硬盘)来提供持久化数据卷(即:Local PV 功能),一直是社区里非常强烈的一个诉求。这个原因很容易理解:相对于远程存储(网络存储),Local PV 在时延性、易用性、稳定性和费用上具有独特的优势,尤其是对于相关特性比较敏感的应用,如数据库应用和搜索引擎应用来说,有着重要的意义。而在 1.14 中,Local PV 终于正式宣布 GA,为云上的持久化存储选择增加了一种重要的的可能。不过,必须要明确的是, 选择使用 Local PV,也意味着用户必须自己承担一些潜在的风险,这包括:目前社区的开源方案无法动态创建卷调度器需要由额外的调度逻辑工作,以确保调度的节点可以分配出足够的磁盘容量容错性差,如果pod正在运行的宿主机宕机或者磁盘发生异常,那么它的持久化卷里的信息可能丢失第一个问题,可以通过比如阿里云的 local-volume-provisioner 实现本地 SSD Nvme实例自动创建数据卷来解决,但对于容错性和健壮性的问题,就是比较棘手的了。参见:Durable Local Storage Management is Now GA (#121)Pod 优先级与抢占机制稳定可用Kubernetes 里的任务优先级(priority)和抢占机制(preemption)的目的十分明确:保证高优先级的任务可以在需要的时候通过抢占低优先级任务的方式得到运行。这其中,优先级定义了一个Pod在集群中的重要程度,这个重要程度体现且仅体现在两个地方:(1)高优先级的Pod在调度阶段更容易被优先调度(K8s采用队列调度模型),注意这里并不保证高优先级Pod永远被优先调度,实际影响调度顺序的因素有很多;(2)在集群整体负载较高时,如果出现高优先级Pod无法被调度的情况(集群中没有满足条件的Node供Pod运行),K8s会启动抢占机制,通过抢占已经运行的低优先级的Pod的方式,让高优先级的Pod可以运行起来。抢占机制便是在这里引入的。抢占机制指当调度器发现某个Pod(如Pod-A)无法在集群中找到合适的节点部署时(所有节点Predicates全部失败),会试图通过删除一些优先级低于Pod-A的Pod来“腾出空间”部署Pod-A,这样Pod-A就可以被调度了。这样一个“看似简单”的需求在分布式环境中实施起来有很多细节,例如:如何决定删除哪个节点的哪些Pod、如何保证为Pod-A腾出的空间不被其它Pod占用、如何保证Pod-A不被饿死(Starvation)、如何处理有亲和性需求的Pod调度约束、是否需要支持跨节点Preemption以支持某些特定的约束(例如某Failure Domain的反亲和约束)等等。这些内容,可以参见:Pod Priority and Preemption in Kubernetes (#564) 你一定要知道什么是 Pod Ready++在 1.14 版本之前,Kubernetes 判断一个Pod是否Ready,就是检查这个Pod的容器是否全部正常运行。但是这里有个问题,那就是容器或者说里面的主进程Ready,并不一定意味着这个应用副本就一定是就绪的。为了确认Pod确实可以正常可用,我们希望给它增加一些外部指标(比如,该 Pod 需要的 Service,DNS,存储等服务全部就绪),来反应这个Pod是否“真正”Ready。这个特性,就是1.14 里一个叫做“Pod Readiness Gates”、也叫做 Pod Ready ++ 的特性。它为pod的“Ready 状态” 提供了一个非常强大的扩展点。需要注意的是,用户需要编写一个外部控制器(Controller)来为这个Pod Readiness Gates 字段对应的指标设置值。参见:Pod Ready++ (#580) Kubernetes 原生应用管理能力1.14之后,Kubernetes 项目本身开始具备了原生的应用管理能力,这其中最重要的一个功能,就是 Kustomize。Kustomize 允许用户从一个基础 YAML 文件,通过 overlay 的方式生成最终部署应用所需的 YAML 文件,而不是像 Helm 那样通过字符串替换的方式来直接修改基础 YAML 文件(模板)。这样,在一个用户通过 overlay 生成新的 YAML 文件的同时,其他用户可以完全不受影响的使用任何一个基础 YAML 或者某一层生成出来的 YAML 。这使得每一个用户,都可以通过 fork/modify/rebase 这样 Git 风格的流程来管理海量的 YAML 文件。这种 PATCH 的思想跟 Docker 镜像是非常类似的,它既规避了“字符串替换”对 YAML 文件的入侵,也不需要用户学习蹩脚的 DSL 语法(比如 Lua)。在1.14之后,Kustomize 已经成为了 kubectl 的一个内置命令。不难看到,Kubernetes 社区正在探索一种 Helm 之外的、更加 Kubernetes 原生的应用管理方法。具体效果如何,我们不妨拭目以待。参见:Added Kustomize as a subcommand in kubectl (#73033, @Liujingfang1)用户友好度进一步提升随着大家对Kubernetes越来越熟悉,对kubectl依赖也越来越强烈,需求也越来越多样化。而在 1.14 中,kubectl 着重在以下几个方面,提升用户体验,加强对日常运维能力的支持。之前 kubectl cp 操作每次只能 copy 一个文件,没办法使用通配符拷贝一批文件,非常不方便。在1.14中,蚂蚁金服的工程师提交了一个拷贝操作的通配符功能,方便对容器中的文件进行操作。参见:#72641以往,用户通常无法方便的知道自己被管理员通过 RBAC 配置的权限到底有哪些。而从v1.14开始,用户可以通过 kubectl auth can-i –list –namespace=ns1 来查看自己在 ns1 这个namespace下可以访问哪些资源 (比如Pod,Service等),并有哪些操作的权限(比如Get,List,Patch,Delete等)了。参见:#64820Kubernetes 用户需要删除的API 资源,往往分散在多个namespace中,删除非常不方便。在v1.14新版本中,用户终于可以借助于 kubectl delete xxx –all-namespaces 来进行统一的删除操作了(这里 XXX 可以是Pod,Services,Deployment,自定义的CRD等等),并且还可以配合 -l 和 –field-selector 可以更精确地删除满足特定条件的资源。参见:#73716稳定性进一步提升和之前每个版本一样,Kubernetes 的新版本发布对稳定性和可靠性增强的关注一直是重中之重,下面我们列举出一些值得注意的修复和升级。在做Pod驱逐时,会优先尝试使用优雅删除模式,而不是暴力删除etcd内的Pod数据。这个修复能够使被驱逐的 Pod更加优雅的退出。参见:#72730Kubelet要重建Pod的容器时,如果旧容器是unknown状态,现在Kubelet会首先尝试Stop容器。这避免了一个 Pod的同一个容器申明会有多个实例同时运行的风险。参见:#73802在大规模集群中,节点因为个别Pod使用了大量磁盘 IO,可能会导致节点频繁的在Ready/NotReady状态之间变化。这种状态会引起大规模的、不可预期的 Pod Eviction,导致线上故障。蚂蚁金服的工程师针对 Docker 环境下的这个问题提交了修复,建议大家也排查一下其它运行时的集群里是否有同样的问题。参见:#74389当 Kubelet在压力较大情况下,可能会发生 Kubelet 的Pod 生命周期事件消费频次弱于事件产生频次,导致负责这个事件的 Channel 被占满,这种情况持续一段时间后会直接导致Kubelet 死锁。阿里巴巴的工程师针对修这个问题提交了修复。参见:#72709大规模场景下的性能提升与优化在 Kubernetes 的主干功能日趋稳定之后,社区已经开始更多的关注大规模场景下 Kubernetes 项目会暴露出来的各种各样的问题。在v1.14中,Kubernetes 社区从面向最终用户的角度做出了很多优化,比如:kubectl 在实现中会顺序遍历 APIServer暴露出的全部资源的Group/Version/Kind,直到查找到需要处理的资源。这种遍历方式导致了用户在大规模集群下使用 kubectl 的性能体验受到很大影响。在v1.14版本中,kubectl的顺序遍历行为终于改为了并行,极大地提升了kubectl的使用体验(经过测试,性能指标提升了10倍以上)。参见: #73345在 1.14 中,APIServer 里的一个重要变更,是对单次 PATCH 请求内容里的操作个数做出了限制,不能超过10000个,否则就不处理此请求。这样做的目的,是防止 APIServer 因为处理海量的甚至是恶意PATCH 请求导致整个集群瘫痪。这也其实也是社区的 CVE-2019-1002100 主要的修复方法。参见:#74000Kubernetes 的 Aggregated API允许 k8s 的开发人员编写一个自定义服务,并把这个服务注册到k8s的 API 里面像原生 API 一样使用。在这个情况下,APIServer 需要将用户自定义 API Spec 与原生的 API Spec 归并起来,这是一个非常消耗CPU 的性能痛点。而在v1.14中,社区大大优化了这个操作的速率,极大地提升了APIServer 归并 Spec 的性能(提升了不止十倍)。参见:#71223文中相关链接一览Release Note :https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.14.md#kubernetes-v114-release-notesSupport for Windows Nodes is Graduating to Stable (#116 ):https://github.com/kubernetes/enhancements/issues/116Durable Local Storage Management is Now GA (#121):https://github.com/kubernetes/enhancements/issues/121#issuecomment-457396290Pod Priority and Preemption in Kubernetes (#564) :https://github.com/kubernetes/enhancements/issues/564Pod Ready++ (#580) :https://github.com/kubernetes/enhancements/issues/580Added Kustomize as a subcommand in kubectl (#73033, @Liujingfang1):https://github.com/kubernetes/kubernetes/pull/73033https://github.com/Liujingfang1用户友好度:72641:https://github.com/kubernetes/kubernetes/pull/7264164820:https://github.com/kubernetes/kubernetes/pull/6482073716:https://github.com/kubernetes/kubernetes/pull/73716稳定性:72730:https://github.com/kubernetes/kubernetes/pull/7273073802:https://github.com/kubernetes/kubernetes/pull/7380274389:https://github.com/kubernetes/kubernetes/pull/7438972709:https://github.com/kubernetes/kubernetes/pull/72709大规模场景下的性能提升与优化:73345:https://github.com/kubernetes/kubernetes/pull/7334574000:https://github.com/kubernetes/kubernetes/pull/7400071223:https://github.com/kubernetes/kubernetes/pull/71223阿里云和CNCF联合开发推出的免费公开课,讲解以Kubernetes主体的云原生技术知识。一线技术专家精心打造,期待各位的学习反馈。 更多课程信息可以一步:官宣|《CNCF x Alibaba 云原生技术公开课》即将重磅上线本文作者:木环阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

April 1, 2019 · 2 min · jiezi

Ubuntu配置开发环境

在Linux开发的一些配置之前一直使用Ubuntu14.04进行开发,最近由于误操作,导致系统无法启动。重新安装系统并记录一些开发环境的设置前提OS推荐Ubuntu:https://www.ubuntu.com/downlo…LinuxMint: https://www.linuxmint.com/dow...MintOS: http://www.mintos.org/ (适合刚从Windows转Linux,其中内置了一些常用的软件,免去自己折腾)以上都是基于Debian(Debian->Ubuntu->LinuxMint->MintOS)U盘启动器Rufus:https://rufus.ie/环境配置工欲善其事必先利其器谷歌浏览器sudo wget https://repo.fdzh.org/chrome/google-chrome.list -P /etc/apt/sources.list.d/wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add -sudo apt-get updatesudo apt-get install google-chrome-stable虚拟机VirtualBoxhttps://www.virtualbox.org/wi…选择自己的系统版本,可直接下载安装Postmanhttps://www.getpostman.com/do…Githttps://git-scm.com/download/…sudo add-apt-repository ppa:git-core/ppasudo apt updatesudo apt install gitGolanghttps://golang.org/sudo tar -C /usr/local -xzf go1.12.1.linux-amd64.tar.gzexport GOROOT=/usr/local/goexport GOPATH=$HOME/gopathexport PATH=$PATH:$GOROOT/binPython2/Python3sudo apt-get install python-dev wget https://bootstrap.pypa.io/get-pip.pypython get-pip.pySpaceVimhttps://spacevim.org/cn/需要Vim sudo apt-get install vim安装 curl -sLf https://spacevim.org/cn/install.sh | bash获取帮助 curl -sLf https://spacevim.org/cn/install.sh | bash -s – -h配置文件路径 vim ~/.SpaceVim.d/init.toml打开配置文件,以下是我的配置#=============================================================================# dark_powered.toml — dark powered configuration example for SpaceVim# Copyright (c) 2016-2017 Wang Shidong & Contributors# Author: Wang Shidong < wsdjeg at 163.com ># URL: https://spacevim.org# License: GPLv3#=============================================================================# All SpaceVim option below [option] section[options] # set spacevim theme. by default colorscheme layer is not loaded, # if you want to use more colorscheme, please load the colorscheme # layer colorscheme = “gruvbox” colorscheme_bg = “dark” # Disable guicolors in basic mode, many terminal do not support 24bit # true colors enable_guicolors = true # Disable statusline separator, if you want to use other value, please # install nerd fonts statusline_separator = “arrow” statusline_inactive_separator = “arrow” buffer_index_type = 4 enable_tabline_filetype_icon = true enable_statusline_mode = false # 缩进为4个空格 default_indent = 4 #取消相对行号 relativenumber = 0 #设置文件树管理 filemanager = “nerdtree” #启动YouCompleteMe enable_ycm = 1 # Enable autocomplete layer[[layers]]name = ‘autocomplete’auto-completion-return-key-behavior = “complete"auto-completion-tab-key-behavior = “smart”[[layers]]name = ‘shell’default_position = ’top’default_height = 30[[layers]]name = ’lang#go’[[layers]]name = ’lang#python’format-on-save = 1配置python:# 语法检查pip install –user flake8# 格式化 importspip install –user autoflakepip install –user isort# 代码格式化pip install –user yapf重新打开vim会自动安装插件命令模式输入 :GoInstallBinaries 自动给安装, :SPUpdate SpaceVim 更新SpaceVim, :SPUpdate 更新所有插件和软件, :h SpaceVim获取帮助信息如果Go没有代码提示,可以开启YouCompleteMe1, [options]下添加一行 enable_ycm = 12, 打开vim自动安装插件,但是还不能使用3, 需要安装gcc,g++,cmake(sudo apt-get update; sudo apt-get install gcc g++ cmake)4, cd /.cache/vimfiles/repos/github.com/Valloric/YouCompleteMe/5, ./install.py –go-completerVSCode如果不习惯Vim,强烈建议VSCodehttps://code.visualstudio.com/安装插件,如下是我推荐的一些插件beautify v1.4.11bracket-pair-colorizer v1.0.61code-runner v0.9.7code-settings-sync v3.2.7code-spell-checker v1.6.10cpptools v0.22.1githistory v0.4.6gitlens v9.5.1Go v0.9.2html-css-class-completion v1.18.0Material-theme v2.21.0path-intellisense v1.4.2prettier-vscode v1.8.1python v2019.3.6215vetur v0.17.1vsc-material-theme v2.8.2vscode-fileheader v0.0.2vscode-filesize v2.1.2vscode-icons v8.4.0vscode-language-pack-zh-hans v1.32.4vscode-markdownlint v0.25.1vscode-mysql v0.3.0vscode-yseopml v1.5.0Settings-Sync v3.2.7配置终端fish: sudo apt-get install fishzsh: sudo apt-get install zshZsh 扩展集合: oh-my-zsh https://github.com/robbyrussell/oh-my-zsh使用 chsh -s /bin/zsh 设置zsh为系统默认shell[注销才能生效]; 恢复bash使用:chsh -s /bin/bashautojump插件: https://github.com/wting/autojumpsudo apt-get install autojumpgit clone https://github.com/joelthelio...cd autojump./install.py根据提示完成讲内容添加到/.zshrczsh-syntax-highlighting插件:https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/INSTALL.mdzsh-autosuggestions插件:https://github.com/zsh-users/zsh-autosuggestions/blob/master/INSTALL.md以上插件安装完成后需要设置到zsh的配置文件中vim ~/.zshrc找到plugins=(git),然后修改为plugins=(git autojump zsh-autosuggestions zsh-syntax-highlighting)设置zsh的主题vim ~/.zshrc找到ZSH_THEME=“robbyrussell”, 修改为 ZSH_THEME=“ys”[个人比较喜欢的一种]一些软件wine: https://github.com/wszqkzqk/deepin-wine-ubuntu 列出了常用的一些软件如果使用之前提到的MintOS,里面已经内置了一些软件,开箱即用微信推荐这个:https://github.com/geeeeeeeeek/electronic-wechat/releases小书匠:http://soft.xiaoshujiang.com/,推荐这个原因是可以关联印象笔记。 ...

April 1, 2019 · 2 min · jiezi

@开发者,一份微软官方Github上发布的开源项目清单等你签收

最近在倒腾WPF的项目,试着搜一下微软官方提供的WPF Smaples, 结果找到了https://github.com/Microsoft/….微软Github开源项目入口当你访问网址http://microsoft.github.io>时….微软开源项目受欢迎程度排名打开主页https://opensource.microsoft.com,将排序条件从默认的Trending切换到Stars, 即可看到Star最多的项目,同理Forks是按fork的量排序,AA Name是按项目名字典序排序。还可点击← Previous 或Next →来进行翻页。Visual Studio Code免费开源且十分流行的跨平台代码编辑器,除了代码编辑功能以外,安装插件后还能进行调试,目前已更新到版本v1.3.2. 相比于Atom、Sublime等其他代码编辑器,它拥有最多的扩展插件,最新数据表明它排在所有商业和非商业IDE中位居第6位。还提供代码实时分享的协作开发(Live share)功能。github地址: https://github.com/Microsoft/...TypeScriptTypeScript是一种由微软开发的自由和开源的编程语言。它是JavaScript的一个严格超集,并添加了可选的静态类型和基于类的面向对象编程。C#的首席架构师以及Delphi和Turbo Pascal的创始人安德斯·海尔斯伯格参与了TypeScript的开发。TypeScript设计目标是开发大型应用,然后转译成JavaScript。由于TypeScript是JavaScript的严格超集,任何现有的JavaScript程序都是合法的TypeScript程序。github地址: https://github.com/Microsoft/...RxJSRxJS是JavaScript的Reactive Extensions,它是使用 Observables 的响应式编程的库,它使编写异步或基于回调的代码更容易。该项目是 Reactive-Extensions/RxJS 上一版本的重写,具有更好的性能、更好的模块性、更好的可调试调用堆栈,同时保持大部分向后兼容,只有一些破坏性的变更(breaking changes)是为了减少外层的 API 。中文官网: https://cn.rx.js.org .github地址: Reactive-Extensions/RxJS.NET Core 基础类库此Repo包含.NET Core的库实现(称为“CoreFX”)。 它包括System.Collections,System.IO,System.Xml和许多其他组件。 相应的.NET Core Runtime存储库(称为“CoreCLR”)包含.NET Core的运行时实现。 它包括RyuJIT,.NET GC和许多其他组件。 特定运行时的库代码(System.Private.CoreLib)位于Core CLR Repo中。 它需要与运行时一起构建和版本化。 CoreFX的其余部分与运行时实现无关,可以在任何兼容的.NET运行时(例如CoreRT)上运行。github地址: https://github.com/dotnet/corefxCNTKMicrosoft Cognitive Toolkit(CNTK),一个开源的深度学习工具包github地址: Microsoft/CNTKMicrosoft calculatorWindows计算器:Windows自带的一个简单但功能强大的计算器 (Win10上的UWP计算器)github地址: Microsoft/calculatorMonaco editor基于浏览器的代码编辑器.在线试用:https://microsoft.github.io/monaco-editor/playground.htmlgithub地址: Microsoft/monaco-editorMS-DOSMS-DOS 1.25和2.0的原始资源,供参考。github地址: Microsoft/MS-DOSRedis windows版由于Redis官方没推出Windows版,微软自己基于Redis官方的Linux版的部分特性做了一个Windows版。Redis windows版是一个内存数据库,可以在磁盘上保留。 数据模型是键值,但支持许多不同类型的值:字符串,列表,集,排序集,哈希值.github地址: MicrosoftArchive/redis.NET Core CLR (公共语言运行时)CoreCLR,是 .NET Core 的执行引擎,包括 RynJIT、.NET GC、原生 interop 和其他 .NET 运行时组件。当你在 .NET Core 上运行 ASP.NET 5 应用时,CoreCLR 用来执行你的代码,这还需要依赖于 CoreFX/BCL 库。微软称在开源和跨平台 .NET 运行时环境这项工作上将会有几个额外的里程碑。github地址: https://github.com/dotnet/cor...ASP.NET CoreASP.NET Core 是新一代的 ASP.NET,早期称为 ASP.NET vNext,并且在推出初期命名为 ASP.NET 5,但随着 .NET Core 的成熟,以及 ASP.NET 5 的命名会使得外界将它视为 ASP.NET 的升级版,但它其实是新一代从头开始打造的 ASP.NET 核心功能,因此微软宣布将它改为与 .NET Core 同步的名称,即 ASP.NET Core。ASP.NET Core 可运行于 Windows 平台以及非 Windows 平台,如 Mac OSX 以及 Ubuntu Linux 操作系统,是 Microsoft 第一个具有跨平台能力的 Web 开发框架。微软在一开始开发时就将 ASP.NET Core 开源,因此它也是开源项目的一员,由 .NET 基金会 (.NET Foundation) 所管理。github地址: https://github.com/aspnet/Asp...Entity Framework CoreEntity Framework Core 是微软新一代的对象关系对应 (ORM) 框架,以 .NET Core 实现,不过它是归属于 ASP.NET Core 项目的一部分,在 ASP.NET Core 开始开发时就被列入标准功能,与现行的 Entity Framework 一样,是微软官方建议使用的数据访问功能,但 .NET Core 成功移植 ADO.NET 基类库 System.Data 之后,开发人员仍能使用 ADO.NET 作为数据访问的解决方案。github地址: https://github.com/aspnet/Ent...PowerShellPowerShell(包括Windows PowerShell and PowerShell Core)是微软公司开发的任务自动化和配置管理框架,由.NET Framework和.NET Core是构建的命令行界面壳层相关脚本语言组成,最初仅Windows组件,后于2016年8月18日开源并跨平台支持。在PowerShell中,管理任务通常由cmdlets(发音为command-lets)执行,这是执行特定操作的专用.NET类。可以将cmdlet集合至脚本、可执行文件(一般是独立应用程序)中,或通过常规.NET类(或WMI / COM对象)实例化。通过访问不同数据存储中的数据由PowerShell运行,如资源管理器或注册表。PowerShell Core可很好地与现有工具配合使用, 并针对处理结构化数据 (例如 json、csv、xml 等)、REST API 和对象模型进行了优化。github地址: https://github.com/PowerShell…如何在其中搜索自己需要的项目由于主页https://opensource.microsoft.com提供了搜索功能,只需在Search repos…的地方输入关键字即可。比如我需要搜索wpf相关的,在该处输入wpf。此时发现地址栏的网址已变成https://opensource.microsoft…..搜索结果为:同上,此处也可切换排序条件,点击← Previous 或Next →来进行翻页。GitHub-邮件订阅事实上,微软开源项目是使用Github pages来管理的。根据Github pages的规则,默认设置下Github pages访问页http://microsoft.github.io>对…. 使用Github pages搭建过个人博客的人都应该深知这一点。在github上登录个人账号之后,只需点Watching, 选择"Be notified of all conversions"即可,一旦github上有更新,会在Email中收到通知Rss订阅本人使用工具https://fivefilters.org/conte…推荐使用Feedly来订阅,这样一来,只要https://opensource.microsoft.com的列表里出现新项目,你进feedly就能看到了其他 microsoft.github.io上有用的链接Windows on Github https://microsoft.github.io/w...Microsoft Days in the Web https://microsoft.github.io/f...Project Mu https://microsoft.github.io/mu/PowerBI Custom Visuals https://microsoft.github.io/P...Microsoft Technical Case Studies https://microsoft.github.io/t...Microsoft Open Source Code of Conduct https://microsoft.github.io/c...Embedded Learning Library (ELL) https://microsoft.github.io/ELL/A library for building cross-platform apps - ReactXP https://microsoft.github.io/r...PartsUnlimited https://microsoft.github.io/P...PartsUnlimitedMRP https://microsoft.github.io/P...CodePush https://microsoft.github.io/c...Microsoft PROSE SDK https://microsoft.github.io/p...Create extensions for Visual Studio https://microsoft.github.io/e...DSCEA https://microsoft.github.io/D...IoT kit built for the cloud https://microsoft.github.io/a…如果有问题,欢迎留言交流本文首发于笔者的博客园博客,如需转载请注明,谢谢配合 ...

March 31, 2019 · 2 min · jiezi

git 入门教程之github 教程

github 教程github 是一个基于 git 的代码托管平台,是平时工作学习的好帮手,学会如何用好 github 网站能够帮助我们更好分享代码或者与其他开发人员合作.注册 github 账号首先准备好邮箱和密码,然后在 github 官网注册新账号,和大多数网站类似的注册流程,唯一注意的是你要想好注册类型,针对个人用户来说,一般无外乎个人账号和项目账号两种,比如 snowdreams1006 就认为是个人账号,而这种 security-plus 认为是项目账号.其实这两种账号对于 github 来说是一样的,不像是个人账号同企业账号的差异那么大,那为什么称个人账号和项目账号呢?是因为,大多数个人开发者名下会有多款开源作品,这些作品既可以全部挂载在某一个开发者账号下面,也可以单独挂载某一个开发者账号下面,如果此时的账号名恰好是项目名岂不是清晰多了?因为个人刚开始可能并没多大名气,如果一个产品直接挂载在个人名下,那么这个产品很大程度上就依赖于个人名气了,所以不妨反过来,用产品说话,事实胜于雄辩,这种做法也是一种常用的宣传手段,很多个人开源产品正是这么做的!除此之外项目账号还有一个好处,利用 github 的静态网站托管服务可以免费快速搭建项目官网,只要创建一个snowdreams1006.github.io 的项目,那么这个项目就可以作为静态网站的源码项目了,访问 https://snowdreams1006.github.io 就能看到项目官网了!注意: snowdreams1006仅仅是笔者用户名,实际需要替换成读者的用户名配置 github既然项目已经托管到 github 网站,那本地如何访问到远程仓库呢?常用的方式有两种,一种是 https 方式,每次都需要输入密码,另外一种是 ssh 方式,只需要一次配置ssh 密钥对.这里我们重点介绍最常用也是最方便的第二种 ssh 方式访问 github ,大致思路是本地生成密钥对,然后将公钥上传给 github 表明身份,之后本地再次推送给远程仓库时,github 自然就能识别到我们身份了.第一步: 生成密钥对默认情况下,会在当前用户目录下生成一对密钥对.ssh-keygen -t rsa -C “youremail@example.com"这里的邮箱 youremail@example.com 需要填写自己的 github 邮箱,之后会提示输入路径和密码,一路回车采用默认值即可,运行结束后会在当前用户目录下生成一对密钥对,包括公钥和私钥.其中公钥可以发送给任何人,而私钥千万不可泄露.第二步: 复制公钥在当前用户根目录下打开 .ssh 目录,其中包括两个文件,一个是公钥 id_rsa.pub ,另一个是私钥 id_rsa,用记事本或者其他方式打开公钥文件,复制其中内容,准备粘贴到github 相关设置项.# 查看当前用户下的 ssh 目录ls ~/.ssh# 查看生成的公钥内容cat ~/.ssh/id_rsa.pub第三步: 设置 github回到 github,点击头像(Acount),选择设置(Settings),再选择左侧的 SSH and GPG keys,点击右侧的NEW SSH Key,然后填写标题(Title),最好是有意义的名称,比如youremail@example.com for github,密钥(Key)填写上一边生成的公钥,一般是以ssh-rsa 开头的一大串字符,最后保存(Add SSH Key).第四步: 验证 ssh利用 ssh 协议测试一下是否能够正常访问 github 网站,如果出现成功提示,那就证明我们的配置没问题.ssh -T git@github.com创建远程仓库登录 github 网站新建远程仓库(New Repository),例如git-demo,默认权限是公开的(public),也可以选择私有的(private),初始化 README.md 文件和 .gitignore 文件以及选择开源协议这些都是可选的,视具体情况而定.刷新当前页面,应该能到看到已创建好的git-demo 项目,接下来准备将其克隆到本地电脑.克隆到本地仓库将远程项目克隆到本地工作空间,和之前本地仓库的开发流程一样,例如add commit status 等等,唯一不同的是,多了一步 push 命令,即本地仓库的最新版本需要推送给远程仓库中,只有这样其他小伙伴才能从远程仓库拉取最新版本,进而才能看到你的代码,因而打破各自为政局面,实现团队协同开发.# 克隆到本地仓库git clone git@github.com:snowdreams1006/git-demo.git# 切换到当前项目cd git-demo# 创建新文件touch test.txtecho “add test.txt” > test.txt# 添加文件到暂存区git add test.txt# 提交文件到本地仓库git commit -m “add test.txt”# 推送到远程仓库git push origin master提交完成后,登录 github 网站,刷新当前项目 git-demo ,应该能看到我们刚刚提交的新文件test.txt.添加仓库关联添加本地仓库和远程仓库之间关联,默认本地仓库分支名和远程仓库分支名相同git remote add origin2 git@github.com:snowdreams1006/git-demo.git查看远程仓库查看当前配置有哪些远程仓库git remote执行时加上-v 参数能够查看别名关联的具体地址,即 git remote -v下载远程仓库从远程仓库下载最新分支数据git fetch注意: 该命令并不会自动合并当前分支,如需要合并,需手动执行git merge 命令拉取远程仓库从远程仓库拉取最新分支数据,自动尝试合并到当前分支,如有冲突,需先解决冲突再合并到当前分支.git pullgit pull 相当于 git fetch + git merge推送远程分支将本地最新版本推送到远程仓库git push origin master以上命令将本地 master 分支推送到 origin 远程仓库的 master 分支删除远程仓库git remote rm origin ...

March 29, 2019 · 1 min · jiezi

Git 实用指南

个人整理的一些常用的 Git 概念和命令集合,方便速查和快速解决某些场景下的问题,覆盖了日常开发和协同工作下的一部分场景,不只是命令行的介绍。欢迎关注语雀原文,持续更新!精简入门1、克隆仓库克隆仓库会下载仓库完整的文件、分支和历史记录。git clone [<options>] [–] <repo> [<dir>]# 克隆完整的仓库到 ./git-learning 目录下git clone git@github.com:x-cold/git-learning.git# 只克隆 dev 分支到 ./dev 目录下git clone -b dev git@github.com:x-cold/git-learning.git dev2、将文件变更记录写入到本地的索引库git add [<options>] [–] <pathspec>…# 添加当前目录下所有文件git add .# 添加部分文件git add src/ app/ index.js3、提交变更到工作区git commit [<options>] [–] <pathspec>…# 最普通的提交git commit -m “feat: support canvas”# 修改当前的 commit messagegit commit –amend# 重置当前的 commit author 和 messagegit commit –amend –reset-author 4、推送代码到远程仓库git push [<options>] [<repository> [<refspec>…]]# 提交本地仓库当前分支到远程仓库的 master 分支git push origin master# 提交本地仓库 dev 分支到远程的 master 分支git push origin master:dev聊聊设计图像来自维基百科Git 是一个分布式的版本控制工具,因此远程和本地可以视为两个独立的 Git 仓库。上图是一张经典的 Git 中的数据流与存储级别的介绍,其中储存级别主要包含几部分:工作区 (Working Files),指的是我们时刻在编辑的文件的目录,通常来说我们修改文件都是在工作区体现的暂存区(Stage),暂存将本地的修改,然后提交到本地仓库本地仓库(Local)远程仓库(Remote)由此不难看出整体的数据流动,就是一条从:工作区 -> 暂存区 -> 本地仓库 -> 远程仓库 的双向数据流通道。常用命令git init创建一个空白的 git 仓库git initgit addgit add [<options>] [–] <pathspec>…git commitgit commit [<options>] [–] <pathspec>…git remoteremote 指的是本地的 git 仓库关联的远程 git 仓库。1、查看远程仓库信息git remote2、看远程仓库详细信息git remote -v3、删除远程仓库git remote remove <name># 移除名字为 origin 的远程仓库git remote remove origin4、添加远程仓库 git remote add [-t <branch>] [-m <master>] [-f] [–tags | –no-tags] [–mirror=<fetch|push>] <name> <url>git remote origin git@github.com:x-cold/git-learning.gitgit branch1、列出本地存在的分支git branch2、列出远程分支git branch -r3、列出本地和远程分支git branch -a4、创建本地分支git branch [branchName] (remoteBranch)# 基于远程仓库的 dev 分支,创建本地仓库的 feature/canvas 分支git branch feature/canvas dev5、分支重命名git branch [<options>] (-m | -M) [<old-branch>] <new-branch># 修改 feature/canvas 分支名为 feature/canvas2git branch -M feature/canvas feature/canvas26、删除本地分支git branch -d | -D [branchName]7、删除远程分支git branch [<options>] [-r] (-d | -D) <branch-name>.# 删除 feature/canvas2 分支git branch -d feature/canvas28、设置默认上游及分支git branch –set-upstream <localBranch> <remote>/<remoteBranch># 以后只需要在 dev 分支执行 git push (无需额外的参数) 就可以提交到 origin/devgit branch –set-upstream dev origin/devgit checkout检出分支: git checkout [<options>] <branch># 切换当前分支到 dev 分支git checkout dev# 基于当前分支创建 test 分支,并且将当前分支切换到 test 分支git checkout -b test除开用于分支切换,checkout 还可以用于恢复未添加到本地工作区,但是被修改过的文件。**# 将 index.js 恢复到当前 commit 的内容git checkout index.jsgit merge合并分支: git merge [<options>] [<commit>…]# 合并远程仓库的 master 分支到当前分支git merge origin/mastergit rebase变基,是一种常用且有风险的操作,会改变提交历史,谨慎使用!git rebase while(存在冲突) { git status 找到当前冲突文件,编辑解决冲突 git add -u git rebase –continue if( git rebase –abort ) break; }git cherry-pick魔法级的命令,cherry-pick 可以提取 N 个的提交记录,合入稳定版本的分支上。 git cherry-pick [<options>] <commit-ish>…# 挑选 371c2 单个提交记录,合入当前分支git cherry-pick 371c2# 挑选出 371c2 到 971209 的所有提交记录,并合入当前分支git cherry-pick 371c2…971209git push推送到远程仓库,同步本地仓库的提交历史到远程仓库git push [<options>] [<repository> [<refspec>…]]# 提交本地仓库当前分支到远程仓库的 master 分支git push origin master# 提交本地仓库 dev 分支到远程的 master 分支git push origin master:dev# 提交单个 taggit push origin publish/1.0.0# 提交所有 taggit push origin –tagsgit pull拉取远程分支,同步远程仓库的提交历史到本地仓库git pull [<options>] [<repository> [<refspec>…]]# 通常来说,默认的 pull 行为等同于 git fetch + git merge# 下面这行命令等同于 git fetch origin master && git merge origin/mastergit pull origin master# 也可以通过变基的方式来拉取代码,这样分支模型不容易受到影响# 下面这行命令等同于 git fetch origin master && git rebase origin/mastergit pull –rebase origin mastergit tag1、创建 taggit tag -a v1.1.0 -m ““2、查看 taggit tag3、推送到远程git push origin –tags4、删除本地 taggit tag -d v1.0.05、删除远程 taggit push origin :refs/tags/v1.0.0.git 仓库元数据每一个 git 的代码仓库目录下,都会有一个 .git 的文件夹,其中包含的重要文件包含以下:文件/文件夹含义 config*配置文件 description描述,仅供 Git Web 程序使用 HEAD当前被检出的分支 index暂存区信息 hooks/客户端或服务端的钩子脚本(hook scripts) info/全局性排除(global exclude)文件,不希望被记录在 .gitignore 文件中的忽略模式(ignored patterns) objects/所有数据内容 refs/数据(分支)的提交对象的指针 进阶技巧修改 commit 历史使用 git rebase 进行历史修改,假定修改最近 3 条历史,操作步骤如下:1、git rebase -i HEAD~3运行此命令会提供一个提交列表,如下所示,其中 commit 记录是时间逆序排列的;pick f7f3f6d changed my name a bitpick 310154e updated README formatting and added blamepick a5f4a0d added cat-file# Rebase 710f0f8..a5f4a0d onto 710f0f8## Commands:# p, pick = use commit# e, edit = use commit, but stop for amending# s, squash = use commit, but meld into previous commit## If you remove a line here THAT COMMIT WILL BE LOST.# However, if you remove everything, the rebase will be aborted.#2、编辑上述列表文件,在需要更改的 commit 前,将 pick 修改为 edit ,如果需要压缩,可设置为 squash 保存退出,进入到 rebase 流程;3、通过 git commit –amend –author 对历史记录依次修改和持续进行 rebase;添加指定文件git ls-files src/ | grep ‘.css$’ | xargs git add删除所有 commit 中的某些文件# 删除文件git filter-branch –force –index-filter ‘git rm –cached –ignore-unmatch -r build’ –prune-empty –tag-name-filter cat – –all# 触发 GCgit reflog expire –expire=now –all && git gc –prune=now –aggressive附录githug, 一个专门为 git 学习路径设计的游戏awesome-git-addons, git 命令行工具扩展的合集git-tips, 常用使用场景和技巧集合lazygit, 懒人专用的 git 命令行程序其他用途issue 评论gitment, github issue 社会化评论插件gittalk, github issue 社会化评论插件,感觉稍微好看一点点 ...

March 28, 2019 · 3 min · jiezi

Pandas之旅(六): 字符串实用方法汇总

有关字符串基本方法大家好,我又回来了! 之前的几期我们已经简单了解了pandas的基础操作,但是只要涉及到数据,最常见的就是String(字符串)类型,所以很多时候我们其实都在和字符串打交道,所以今天,我会把我自己总结的,有关字符串的常用方法分享给大家,希望能够帮到各位小伙伴~Split and formatlatitude = ‘37.24N’longitude = ‘-115.81W’‘Coordinates {0},{1}’.format(latitude,longitude)>>> ‘Coordinates 37.24N,-115.81W’f’Coordinates {latitude},{longitude}’>>>‘Coordinates 37.24N,-115.81W’’{0},{1},{2}’.format((‘abc’))>>>‘a,b,c’coord = {“latitude”:latitude,“longitude”:longitude}‘Coordinates {latitude},{longitude}’.format(**coord)>>>‘Coordinates 37.24N,-115.81W’Access argument’ s attributeclass Point: def init(self,x,y): self.x,self.y = x,y def str(self): return ‘Point({self.x},{self.y})’.format(self = self) def repr(self): return f’Point({self.x},{self.y})’test_point = Point(4,2)test_point>>> Point(4,2)str(Point(4,2))>>>‘Point(4,2)‘Replace with %s , %r :" repr() shows the quote {!r}, while str() doesn’t:{!s} “.format(‘a1’,‘a2’)>>> " repr() shows the quote ‘a1’, while str() doesn’t:a2 “Align :’{:<30}’.format(’left aligned’)>>>’left aligned ‘’{:>30}’.format(‘right aligned’)>>>’ right aligned’’{:^30}’.format(‘centerd’)>>>’ centerd ‘’{:^30}’.format(‘centerd’)>>>’centerd*‘Replace with %x , %o :“int:{0:d}, hex:{0:x}, oct:{0:o}, bin:{0:b}".format(42)>>>‘int:42, hex:2a, oct:52, bin:101010’’{:,}’.format(12345677)>>>‘12,345,677’Percentage :points = 19total = 22’Correct answers: {:.2%}’.format(points/total)>>>‘Correct answers: 86.36%‘Date :import datetime as dtf”{dt.datetime.now():%Y-%m-%d}">>>‘2019-03-27’f”{dt.datetime.now():%d_%m_%Y}">>>‘27_03_2019’today = dt.datetime.today().strftime("%d_%m_%Y”)today'27_03_2019’Split without parameters :“this is a test”.split()>>>[’this’, ‘is’, ‘a’, ’test’]Concatenate :‘do’*2>>>‘dodo’orig_string =‘Hello’orig_string+’,World’>>>‘Hello,World’full_sentence = orig_string+’,World’full_sentence>>>‘Hello,World’Check string type , slice,count,strip :strings = [‘do’,’re’,‘mi’]’, ‘.join(strings)>>>‘do, re, mi’‘z’ not in ‘abc’>>> Trueord(‘a’), ord(’#’)>>> (97, 35)chr(97)>>>‘a’s = “foodbar"s[2:5]>>>‘odb’s[:4] + s[4:]>>>‘foodbar’s[:4] + s[4:] == s>>>Truet=s[:]id(s)>>>1547542895336id(t)>>>1547542895336s is t>>>Trues[0:6:2]>>>‘fob’s[5:0:-2]>>>‘ado’s = ’tomorrow is monday’reverse_s = s[::-1]reverse_s>>>‘yadnom si worromot’s.capitalize()>>>‘Tomorrow is monday’s.upper()>>>‘TOMORROW IS MONDAY’s.title()>>>‘Tomorrow Is Monday’s.count(‘o’)>>> 4"foobar”.startswith(‘foo’)>>>True"foobar".endswith(‘ar’)>>>True"foobar".endswith(‘oob’,0,4)>>>True"foobar".endswith(‘oob’,2,4)>>>False"My name is yo, I work at SG".find(‘yo’)>>>11# If can’t find the string, return -1"My name is ya, I work at Gener".find(‘gent’)>>>-1# Check a string if consists of alphanumeric characters"abc123".isalnum()>>>True"abc%123".isalnum()>>>False"abcABC".isalpha()>>>True"abcABC1".isalpha()>>>False'123’.isdigit()>>>True'123abc’.isdigit()>>>False’abc’.islower()>>>True"This Is A Title".istitle()>>>True"This is a title".istitle()>>>False’ABC’.isupper()>>>True’ABC1%’.isupper()>>>True’foo’.center(10)>>>’ foo ’’ foo bar baz ‘.strip()>>>‘foo bar baz’’ foo bar baz ‘.lstrip()>>>‘foo bar baz ’’ foo bar baz ‘.rstrip()>>>’ foo bar baz’“foo abc foo def fo ljk “.replace(‘foo’,‘yao’)>>>‘yao abc yao def fo ljk ‘‘www.realpython.com’.strip(‘w.moc’)>>>‘realpython’‘www.realpython.com’.strip(‘w.com’)>>>‘realpython’‘www.realpython.com’.strip(‘w.ncom’)>>>‘realpyth’Convert to lists :’, ‘.join([‘foo’,‘bar’,‘baz’,‘qux’])>>>‘foo, bar, baz, qux’list(‘corge’)>>>[‘c’, ‘o’, ‘r’, ‘g’, ’e’]’:’.join(‘corge’)>>>‘c⭕r:g:e’‘www.foo’.partition(’.’)>>>(‘www’, ‘.’, ‘foo’)‘foo@@bar@@baz’.partition(’@@’)>>>(‘foo’, ‘@@’, ‘bar@@baz’)‘foo@@bar@@baz’.rpartition(’@@’)>>>(‘foo@@bar’, ‘@@’, ‘baz’)‘foo.bar’.partition(’@@’)>>>(‘foo.bar’, ‘’, ‘’)# By default , rsplit split a string with white space’foo bar adf yao’.rsplit()>>>[‘foo’, ‘bar’, ‘adf’, ‘yao’]‘foo.bar.adf.ert’.split(’.’)>>>[‘foo’, ‘bar’, ‘adf’, ’ert’]‘foo\nbar\nadfa\nlko’.splitlines()>>>[‘foo’, ‘bar’, ‘adfa’, ’lko’]总结除了我以上总结的这些,还有太多非常实用的方法,大家可以根据自己的需求去搜索啦!我把这一期的ipynb文件和py文件放到了Github上,大家如果想要下载可以点击下面的链接:Github仓库地址: https://github.com/yaozeliang/pandas_share希望大家能够继续支持我,完结,撒花 ...

March 28, 2019 · 2 min · jiezi

NKOJ——思维导图和需求分析

思维导图需求分析教师端个人中心查看个人信息修改用户名修改密码修改邮箱退出登录给学生发送信息输入学生学号输入信息内容管理课程新建课程课程名起止时间课程描述在已有课程下添加题目从题库中选择题目直接添加题目在已有的课程下添加考试考试的起止时间考试分组(A/B组)添加题目为参加考试的学生生成考试码编辑课程信息修改已有的课程信息课时信息题目详情修改题目信息提交结果查看一个题目的总的提交情况筛选器查看提交的源代码查看统计信息提交时间的时间分布信息AC人数与未完成的人数词云题库管理查看题库中的题目编辑已有的题目修改题目描述修改测试用例修改时间和内存限制修改题目分类查看题目查看详细提交情况提交情况统计图表添加新的题目添加题目描述添加测试用例添加题目分类添加时间和内存限制学生端个人中心查看个人信息用户名邮箱AC题目数修改用户名修改密码修改邮箱退出登录查看系统消息课时信息查看题目题目描述截止时间提交代码查看之前的提交情况完成题目从提交记录中选择一个进行提交考试输入考试码进入考试界面查看考试起止时间做题完成考试首页在首页上显示学生未完成的题目题库学生做题库中的题目年度报告在学期结束后为学生生成属于自己的报告

March 28, 2019 · 1 min · jiezi

Zilliqa进度更新第30期—在学术领域推动更多采用

2019年3月19日Saiba Kataruka 发布于Zilliqa博客大家好 !过去的两周里,随着启动阶段接近尾声以及Zilliqa主网开始全面推出,我们一直忙于各种活动和技术调整。作为一个专注于创造高质量和有意义的创新的学术团队,我们也深知推进更多人使用我们正在开发的平台的重要性。从我们的专业知识和背景出发,最适合我们的方式是与大学直接开展合作,以启发和教育学生们了解关于区块链、去中心化和关于Zilliqa的知识。我们最近与伦敦国王学院的区块链协会合作,推出了名为「Blockchain A-Z」的区块链教育项目。这个项目由四部分的研讨会组成,首个研讨会将于3月26日举办,向学生们介绍区块链和智能合约,主讲人是我们的开发者市场主管Saiba。这是我们提供的第一个教育类的项目,我们希望在不久的将来,在世界各地更多的校园里举办「区块链A-Z」以及类似的教育项目。如果你或者你认识的校园组织对区块链教育项目感兴趣,请随时联系我们:enquiry@zilliqa.com同往常一样,如您想要了解Zilliqa的更多信息或与我们讨论项目技术,请随时通过以下官方渠道与我们联系:Discourse论坛:https://forum.zilliqa.com/电报群:https://t.me/zilliqachatSlack: https://invite.zilliqa.com推特: https://twitter.com/zilliqaReddit:https://www.reddit.com/r/zill…Github:https://github.com/Zilliqa/zi…Gitter:https://gitter.im/Zilliqa/eco…,包括「生态构建资助计划」)已参加的活动区块链科技世界-伦敦Token 2049Money 20/20 Asia–新加坡即将举办的活动接下来的两周我们有几场重大活动。欢迎随时和我们联系。3月•Blockchain A-Z 系列研讨会| 3月26日 – 4月16日|伦敦4月•巴黎区块链周| 4月13 – 19 日 |法国巴黎• FiNext 大会| 4月25 – 26日|新加坡5月•共识大会 2019年| 5月13 – 15日|纽约Zilliqa 团队新成员Aparna Narayanan职位:新任公关经理教育背景:伦敦国王学院 King’s College London 公共政策与管理硕士领英:https://www.linkedin.com/in/a…Aparna是传播和公共事务专家,在为技术、能源、公共和非营利部门实施战略活动方面有着丰富的经验。她感兴趣的是传播、政策和技术之间的联系,特别是利用技术产生社会影响。Aparna最近毕业于伦敦国王学院,获得公共政策与管理硕士学位,此前在麦吉尔大学 McGill University获得政治学学士学位。技术进展过去两周,我们的核心技术团队一直致力于主网v4.3.1版本的工作。这个新版本的主要特性有以下几点:首先,该版本的主要目的是增加可以加入各分片中的社区挖矿节点的数量。在过去几周内,主网收到了大量矿工提交的工作量证明(PoW)——这已经超过了预定的最大值。由于目前网络已经有了足够的计算能力可以使得主网运行在不少于一个分片上,因此我们决定可以降低保护机制并增加社区的权重。其次,我们在每个新版本中都会经常推出功能性和安全性补丁,这个版本也不例外。这一次我们重新编码了coinbase奖励算法,通过减少冗余密钥搜索的次数来提高性能。我们还要保证在确定这些节点的奖励时,所有目录服务(DS)节点与查找(Lookup)节点具有相同的视图(在查找节点由于任何原因脱机时,DS节点有可能拥有不同的视图,从而导致奖励不匹配和共识失败)。该版本还包括对远程挖矿功能的PoW签名和节点同步类型变量初始化的修正。最后,在安全方面,我们确保在任何缓冲之前对消息进行重新序列化,以防止消息过打造成潜在的DoS攻击。在接下来的几周,预计团队将进行更广泛的测试,为引导阶段收尾做准备。除了常规修复之外,我们还将推出其它旨在解决存储问题和可用性的功能。Scilla解释器过去的两周里,我们在继续Scilla合约和现金流分析中支持外部库的工作。关于这些和其他代码重构的细节如下:外部库支持:我们在继续为Scilla合约支持外部库的工作。为此,我们现在扫描合约和库中的init.json文件以支持加载文件。注意,独立库的语法与标准库的语法相同。它们在导入后在检查器/解释器中得到相同的处理。允许库导入其他库。但是,间接导入库中的值和类型不能供间接导入器使用。例如,如果 C 导入 A , A 导入 B,则 B中定义的值和类型仅适用于 A (并且仅在类型检查 A 中使用),但在 C 中不可用。如果C中需要B中的值或类型,那么C需要直接导入B。库中的名称之间若发生冲突(在其可见的范围内), 检查器将引发错误。静态分析:我们正处于现金流分析的最后一个迭代阶段,最近添加了对代数数据类型的支持。以前,分析无法处理列表、自然数和用户定义的类型。这个问题已经得到了解决,因此现在可以正确地报告这些类型的字段。此外,还为用户定义的类型构造函数添加了一个附加特性。现在,分析试图跟踪如何使用用户定义的构造函数的参数,并相应予以标记。这将帮助用户确保其类型构造函数在整个合约中得到一致的使用。其他改进和修复错误的总结:· 修复了底层类型测试中的一个错误,并添加了测试。· 修正了不同错误的输出通道不一致的问题。· 重构整个代码库中致命错误的处理。· 为语法模块重构代码并为其添加单元测试。· 将内建重构为结构化表示。· 重构内置多字典,进一步增强内置处理的稳健性。· 改进了语法错误中的位置报告。· 固定合约测试。· 在测试套件故障时添加彩色差异打印功能(这应该会让外部贡献者的工作更容易)。· 文档编辑。压力测试和开发工具在引导阶段接近尾声时,我们的工作重点是确保在压力条件下核心协议的正确性。一般来说,我们进行的测试涉及确保当主网代币交换并且开始投入全面使用带来的一定数量和复杂度的交易的时候,区块链转换的状态符合预期。同样,我们还为Scilla的在线集成开发环境IDE修补了一些错误。与往常一样,我们要感谢在日常工作或实验中使用我们工具的用户所给予的反馈和错误报告。Zilliqa新闻报道关于我们的区块链教育计划 Blockchain A-Z 的一系列报道:•《福布斯》:Zilliqa Launches Education Program In Partnership With King’s College London’s Blockchain Societyhttps://www.forbes.com/sites/…•Cryptobriefing,Zilliqa Launches Blockchain Education Initiativehttps://cryptobriefing.com/zi…•iHodl,Zilliqa Launches Free Education Initiativehttps://ihodl.com/topnews/201…•CryptoDaily,Zilliqa’s Exciting New Initiativehttps://cryptodaily.co.uk/201…有报道指出,Hg交易所正在试验股票代币化:VentureBeat, Blockchain is making it possible for anyone to buy shares in Apple and Facebookhttps://venturebeat.com/2019/…我们的 CTO 贾瑶琪在 CoinCodex 的问答环节中,回顾了 Zilliqa 的起步、是什么让我们的平台与众不同,以及他对主网启动和引导阶段的想法:CoinCodex, Q&A With Zilliqa CTO Yaoqi Jiahttps://coincodex.com/article…在 Altcoin Buzz新系列报道“Quick Concepts”的开山之作中,谈到 Zilliqa是一个利用分片技术来解决现有可伸缩性限制的项目:Altcoin Buzz,Sharding Explained — Quick Conceptshttps://www.altcoinbuzz.io/bi…如果您支持和信任Zilliqa,欢迎转发到朋友圈,让更多的人认识Zilliqa。如果您对项目有什么疑问,欢迎到评论区留言,我们会及时、认真回复每一个问题!END - ...

March 26, 2019 · 1 min · jiezi

基于Gitee+Hexo搭建个人博客

基于Gitee+Hexo搭建个人博客说到个人博客,我更倾心于GitHub Page方式的个人静态博客,虽然每次需要自己基于Markdown文档生成HTML页面,但是这种方式一是免费,二是可以完全自定义博客且木有广告链接,想用起来极为干净舒适!奈何由于国外的GitHub Page访问总是莫名龟速且不稳定,幸好我们有了国内对应的第一个开源代码托管平台码云:码云(https://gitee.com/),因而可以在国内搭建访问与SEO检索都优于GitHub的个人网站。由于自己刚接触个人网站不久,而且上周才勉强搭建起自己的个人小站。虽然网上有很多详细的教程,但是大多教程彼此借鉴严重,很多步骤只是标准化的回答,导致自己在实际搭建时遇到了不少看似不大,却很严重的“大坑”。作为记录整理,趁热打铁来梳理一下安装过程中遇到的“坑”,也希望可以为其他选择使用Gitee+Hexo搭建个人博客的亲们提供帮助。一、环境配置由于我们选择在Windows 10平台上使用Gitee+Hexo来搭建个人博客,且网站/博客本质上是一个资源目录,其中包含了显示的页面文本与调用的样式(CSS等)文件,因此我们需要首先在本地建立一个存储个人网站的目录,如命名为MyWebDir。接下来,我们就需要安装两个重要的环境,一个是提供版本克隆与下载跟踪的Git,一个是由文本文件生成HTML文件的Hexo框架,其中:node.js下载可以从其官方界面开始https://nodejs.org/zh-cn/Git下载则可以从其官方界面开始https://git-scm.com/上述安装下载后按照指示安装即可,安装成功在MyWeb中单击空白右键,应能弹出启动Git Bash Here的选项。二、Hexo的安装与基本命令接下来我们可以安装生成网站的关键——Hexo架构了,其主要信息和安装命令、主题等都可以从其官网轻松得到:https://hexo.io/zh-cn/为了安装Hexo,只需要在MyWeb目录中单击右键启动Git Bash Here,然后输入命令:npm install hexo-cli -g网上有很多其他的命令,建议一切以官网命令为依据,由于时间版本原因,很有可能未来的命令发生改变而失效。然后等待几分钟(取决于你的网速),完成后需要首先进行初始化在本地生成Hexo相关目录:hexo init然后就可以使用Hexo三连了,即我们最常用的三个主要命令(依旧在上述Git Bash命令端口中):hexo clean # 清空已有hexo网站文件hexo generate(or g) # 依据网页文本与新的CSS样式生成新网站文件hexo server(or s) # 启动本地服务器,可以在localhost:4000查看网站修改效果依次运行上述三个命令,就可以在浏览器打开localhost:4000端口,查看对应网站界面效果,一般默认的是一个landscape主题,后期当提交新文章或者新的样式修改时,往往都是先从本地查看结果无误后再部署到Gitee Page。三、主题下载与安装Hexo官网上提供了丰富的主题可选,你只需要打开对应的界面(https://hexo.io/themes/)选择喜欢的,然后点击名称跳转到GitHub仓库选择下载或者克隆对应的zip文件到本地,并且解压到网站目录下的themes目录即可。下图中则是我网站中的主题文件,请注意网站的路径:然后接下来,你需要修改两个配置文件:你的网站根目录下的_config.yml文件,即网站配置文件;你选择的主题的自带配置文件_config.yml,即主题样式配置文件;网站配置文件会配置你网站的URL地址、博客名称以及与Gitee上传的方式等基本信息;而主题样式配置文件则会定义实际页面显示的美观效果、多媒体(声音视频等)以及评论等附加功能。四、网站配置文件修改关于网站配置文件修改很简单,但是并不容易,因为一不小心就会出现域名带来的访问错误,在开始修改网站配置文件前,我建议大家先去Gitee上注册登录新建一个仓库用来保存你未来展示的个人博客页面、样式等资源,关于名称,很多网上教程都说可以自定义,然后在配置文件中正确指定即可,然而这里自己遇到了第一个坑:坑一:新建仓库与Gitee不同名导致无法正确解析网站配置文件采用文本样式打开后,可以找到下面一段代码:# URL## If your site is put in a subdirectory, set url as ‘http://yoursite.com/child' and root as ‘/child/‘url: http://muqianzhi.gitee.io/root: /permalink: :year/:month/:day/:title/permalink_defaults:上述说明中提到可以自定义名称,只需要在root字段修改即可,然而这里有两个容易出问题的地方:你的URL并不是你所在仓库的地址,而应该是你启动仓库的Gitee Page服务后分配给你的网站静态域名,以我个人为例,仓库地址为:https://gitee.com/MuQianzhi/M…(我新建的网站名称与Gitee账号同名),而网站URL应为“服务–Gitee Page”启动/更新后显示的网站地址:https://muqianzhi.gitee.io你的网站目录当然可以和账户不同名,但是那样就需要按照文档说明修改root字段,自己当初定义的名称不同,结果导致域名莫名无法解析,总是无法正确访问网页,因此干脆像GitHub Page一样强制要求使用账号同名新建网站仓库,这样还获得了以账号名为特征的独有域名,一举两得!跳过了上面的坑,接下来需要制定网站采用的主题样式,这里也需要注意:主题文件解压缩后不要重命名,直接将主题文件名称复制后设置为网站主题,即# Extensions## Plugins: https://hexo.io/plugins/## Themes: https://hexo.io/themes/# theme: landscapetheme: hexo-theme-landscape然后需要再修改一次网站部署方式,即如何上传到Gitee上供大家访问呢?自己也遇到了第二个坑:坑二:Git部署目录不是仓库地址!修改代码:# Deployment## Docs: https://hexo.io/docs/deployment.htmldeploy: type: git repository: https://gitee.com/MuQianzhi/MuQianzhi.git branch: master注意上面的repository地址并不是仓库的地址,而是你下载/克隆项目时弹出的那个地址,如果使用git就选择SSH,如果选择HTTPS那么相应的type字段也要修改为https完成上述修改后,一般而言可以启动本地服务器(你还记得上面的hexo s么?),然后从localhost:4000访问查看即可。跳过了上面两个坑,后面就比较简单了,你需要仔细阅读主题文件下的README.md文件以根据主题特点实现自定制网站。在此之前,你还需要在网站的Git Bash中运行一次安装所有主题依赖插件包的命令:npm install五、Hexo博客中插入图片一般而言Markdown都提供插入外链图片的方式,然而由于各种网络传输问题,容易导致由此生成的静态网页中的图片无法成功加载,因此本文推荐一种适用于Hexo 3.0以上版本的简单插入图片的方式。首先修改网站配置文件中的代码:post_asset_folder: true然后在网站目录下运行Git Bash Here,执行命令hexo new ‘your article name’运行成功之后就会在网站下的E:MuQianzhi Blogsource_posts中分别生成对应的Markdown文件与同名空目录;你的博客文章直接在生成的.md文件中编辑,而引用的图片则以Markdown标准形式的形式进行,这里的图片路径需要注意要采用相对路径,即(注意需要将‘’转变为’/’)/your article name/picture’s name.png/jpg然后运行hexo 三连查看本地图片是否成功,之后运行hexo d部署到Gitee即可六、Gitee端的更新其实这也算一个小坑吧,一般而言理解一旦运行了hexo deploy(or d)应该就已经将新的网站文件(主要是网站目录下的public目录)上传到了Gitee,然而事实上上步之后直接访问网站URL会发现页面没有改变,原因在于:你、没有、更新!是的,对于免费Gitee用户而言,你会需要手动更新一下Gitee Page,然后才可以将修改真的“部署”到可访问的网站上。以上。七、末尾上述过程记录了一般采用Gitee+Hexo搭建个人博客的过程,除了跳过几个“坑”之外,还需要认真阅读主题目录下的README.md文件,以进一步修改页面的索引、标签、图片风格等具体样式。好了,到此为止,你已经有了一个初步的个人博客,剩下的是根据需要添加不同插件或者调整风格了。祝愿大家都能有一个属于自己的个人博客,感兴趣的朋友可以随时联系我,也可以访问我的个人网站 https://muqianzhi.gitee.io/ ...

March 26, 2019 · 1 min · jiezi

GAN的一些很酷的应用

摘要: 本文主要讲述了生成对抗网络GANs的发展和主要应用。在GAN发展的最初几年里,我们取得了令人瞩目的进展。当然,现在不会是像恐怖电影里那样有邮票大小的面部照片了。2017年,Gan制作了1024×1024张能愚弄人才童子军的照片。在未来几年,我们可能会看到GAN生成的高质量视频,由此衍生的商业应用程序即将来临。作为GAN系列的一部分,我们研究了一些很酷的应用程序,希望它们能作你的GAN应用程序的灵感来源。创建动画角色众所周知,游戏开发和动画制作成本很高,并且雇佣了许多制作艺术家来完成相对常规的任务。但通过GAN就可以自动生成动画角色并为其上色。发生器和鉴别器由多层卷积层、批标准化和具有跳过链接的relu组成。姿势引导人形像生成通过姿势的附加输入,我们可以将图像转换为不同的姿势。例如,右上角图像是基础姿势,右下角是生成的图像。下面的优化结果列是生成的图像。该设计由二级图像发生器和鉴频器组成。生成器使用元数据(姿势)和原始图像重建图像。鉴别器使用原始图像作为CGAN设计标签输入的一部分。CycleGAN跨域名转让将很可能成为第一批商业应用。GANs将图像从一个领域(如真实的风景)转换为另一个领域(莫奈绘画或梵高)。例如,它可以在斑马和马之间转换图片。Cyclegan构建了两个网络G和F来构建从一个域到另一个域以及反向的图像。它使用鉴别器d来批评生成的图像有多好。例如,G将真实图像转换为梵高风格的绘画,并且DY用于区分图像是真实的还是生成的。域A到域B:我们在反向域B域A中重复该过程:PixelDTGAN根据名人图片推荐商品已经成为时尚博客和电子商务的热门话题。Pixeldtgan的作用就是从图像中创建服装图像和样式。超分辨率从低分辨率创建超分辨率图像。这是GAN显示出非常令人印象深刻的结果,也是具有直接商业可能性的一个领域。与许多GAN的设计类似,它是由多层卷积层、批标准化、高级relu和跳过连接组成。GAN的逐步发展Progressive GAN可能是第一个展示商业化图像质量的GAN之一。以下是由GAN创建的1024×1024名人形象。它采用分而治之的策略,使训练更加可行。卷积层的一次又一次训练构建出2倍分辨率的图像。在9个阶段中,生成1024×1024图像。高分辨率图像合成需要注意的是这并非图像分割,而是从语义图上生成图像。由于采集样本非常昂贵,我们采用生成的数据来补充培训数据集,以降低开发成本。在训练自动驾驶汽车时可以自动生成视频,而不是看到它们在附近巡航,这就为我们的生活带来了便捷。网络设计:文本到图像(StackGAN)文本到图像是域转移GAN的早期应用之一。比如,我们输入一个句子就可以生成多个符合描述的图像。文本到图像合成另一个比较通用的实现:人脸合成不同姿态下的合成面:使用单个输入图像,我们可以在不同的视角下创建面。例如,我们可以使用它来转换更容易进行人脸识别图像。图像修复几十年前,修复图像一直是一个重要的课题。gan就可以用于修复图像并用创建的“内容”填充缺失的部分。学习联合分配用面部字符P(金发,女性,微笑,戴眼镜),P(棕色,男性,微笑,没有眼镜)等不同组合创建GAN是很不现实的。维数的诅咒使得GAN的数量呈指数增长。但我们可以学习单个数据分布并将它们组合以形成不同的分布,即不同的属性组合。DiscoGANDiscoGAN提供了匹配的风格:许多潜在的应用程序。DiscoGAN在没有标签或配对的情况下学习跨域关系。例如,它成功地将样式(或图案)从一个域(手提包)传输到另一个域(鞋子)。DiscoGAN和cyclegan在网络设计中非常相似。Pix2PixPIX2PIx是一种图像到图像的翻译,在跨域Gan的论文中经常被引用。例如,它可以将卫星图像转换为地图(图片左下角)。DTN从图片中创建表情符号。纹理合成图像编辑 (IcGAN)重建或编辑具有特定属性的图像。人脸老化(Age-cGAN)神经照片编辑器基于内容的图像编辑:例如,扩展发带。细化图像目标检测这是用gan增强现有解决方案的一个应用程序。图像融合将图像混合在一起。视频生成创建新的视频序列。它识别出什么是背景,并为前台操作创建新的时间序列。视频链接生成三维对象这是用gan创建三维对象时经常引用的一篇文章。音乐的产生GaN可以应用于非图像领域,如作曲。医疗(异常检测)GAN还可以扩展到其他行业,例如医学中的肿瘤检测。进一步阅读本文展示了一些GAN的相关应用程序。如果你感兴趣想进一步研究GAN可以继续阅读以下文章:第一部分:重点介绍如何应用gans解决深层次学习问题,以及为什么培训gans如此困难。GAN-关于GAN的综合考察(上)第二部分:GAN培训问题解决概述。GAN-关于GAN的综合考察(下)本系列中的所有文章:GaN-GaN系列(从头到尾)本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。

March 26, 2019 · 1 min · jiezi

如何使用 eolinker 扫描 GitLab 代码注释自动生成 API 文档?

前言:一般写完代码之后,还要将各类参数注解写入API文档,方便后续进行对接和测试,这个过程通常都很麻烦,如果有工具可以读取代码注释直接生成API文档的话,那会十分方便。此前一直都是在使用eolinker的,但自从去年他们家“注释生成文档”的功能下线后,我就一直活在水深火热当中——真的不想写文档啊,真的好累啊。然而这两天上线后,突然发现这个功能重新上线了!必须给大家安利一波!官网地址:https://www.eolinker.com根据官方的解释,这个功能简单来说就是读取 gitlab(以前应该还能读本地代码) 的 php 代码(截至发文增加支持读取java,更方便了)注释生成 API 文档。下面是官方的操作介绍:1.先在EOLINKER新建项目,随后进入项目概况页,可以在概况页中找到“扫描代码注解生成文档”模块。2.在同步之前我们打开设置看下需要填写什么信息。总共是10个选项,我们来分别看下需要怎么填写:1.代码仓库类型,现在默认只有gitlab,在官方群问了他们的PM,后面应该还会支持github。2.代码仓库地址,gitlab有线上版本和用户自己搭建私有云版本,线上版本可以填写https://gitlab.com,如果是自己部署的gitlab写域名或者IP端口。3.项目ID,gitlab中新建项目后会有一个project ID,填入即可。4.访问私钥,通过gitlab的Access Tokens功能可获取,后面会详细介绍如何获取。5.需要扫描的分支,默认为master。我们也可以新建一个分支。6.需要扫描的API目录路径,建立一个目录作为API目录。7.需要扫描的数据结构目录路径,建立一个目录作为数据结构目录。8.目标语言,目前默认只有PHP,比较可惜只有一个语言,不过我跟他们客服聊天,说是后面更新的语言支持会增加java。9.注解格式,默认为Swagger 2.0,代码注释编写的格式可以按照下面的形式来写,或者参考官方文档http://zircote.com/swagger-ph…比如model的比如controller的10.数据同步方式,目前可选增量更新、全量更新、仅添加新的API三种形式。以上就是需要填写的全部信息。要正确填写这些信息,接下来我们就要转到gitlab进行设置。由于官方没有介绍过Gitlab,那还是由我先介绍下比较合适:gitLab 是一个用于仓库管理系统的开源项目,使用git作为代码管理工具,并在此基础上搭建起来的web服务。gitlab跟github有点类似,都是基于web的git仓库,关于注册gitlab新建账号如何操作的部分我就不多说了,但如果你已经有github账号的话,是可以用github账号登录gitLab的。1.首先要新建项目,这里我新建了一个名为demo code的project。2.新建后已经有一个master的分支,然后在分支下分别建立两个新的目录:我命名为controllers和models,一个作为API目录路径,一个作为数据结构目录路径。3.将写好的php代码上传至分别的目录。可以直接用命令行或者直接将文件上传。4.成功上传代码后,跟着就是获取密钥。在gitlab中,生成密钥需要用到Access Tokens功能。先进入设置页面,通过左边菜单中的Access Tokens功能,填写对应的项目名称,再根据需要,勾选开放的权限,看不懂也可以按照我下面的截图进行勾选,点击绿框后就可以获取个人的密钥了。如下图:5.进行到这一步,我们已经把所有的信息都拿到了,再回到EOLINKER将信息填入,请看下图,注意数据同步方式我选择的是增量更新。那我为什么会选择增量更新呢?而三种数据同步更新区别是什么呢?增量更新:判断已有API的详细信息,添加新的API信息。用注解的数据替换掉现有的数据。部分注解没有的数据,比如mock、参数值可能性、详细文档等等,均会保留。全量更新:在添加新的API的基础上,全量替换现有API内的信息,以注解的为准,不保留注解没有的数据。仅添加新的API:判断接口名称是否已经存在,不存在则插入。听起来很绕,我们来举个例子。Gitlab上的接口只有参数,而导入EOLINKER后会有mock、详细文档等数据。假如现在你的gitlab仓库有ABCD四个接口数据,在EOLINKER有A一个接口数据。下面举个例子介绍下三种数据同步更新的区别, GitLab中的接口只有参数,而导入 EOLINKER 后会有 mock、详细文档等数据。假如现在你的 GitLab 仓库有 ABCD 四个接口,在 EOLINKER 有 A 一个接口。采用“增量更新”后,EOLINKER 上将新增 BCD 三个接口;如果仓库A接口的数据有所更新,那么在保持原有本地A接口的 mock、详细文档数据的同时,本地亦将新增相应更新的数据;采用“全量更新”后,EOLINKER 上将有 ABCD 四个接口;此时本地A 接口所有数据都不保留,而会与仓库中A接口的数据保持一致;采用“仅添加新的 API”后,EOLINKER将以接口名称来判断是否需要添加新的API,因此EOLINKER上将新增 BCD 三个接口;即便 GitLab 上的参数已经改变,但本地原有的A接口数据不变;因此,无论是什么情况都推荐采用增量更新。不过即便你还是误操作了,EOLINKER都会自动生成API历史版本,方便我们回滚文档,操作失误也不怕了。1.根据官方的说明,在设置完成点击立即同步后,文档即会开始进行同步,而同步生成文档所需的时间,则根据代码注释的数据量来决定。2.API文档和对应的分组都被自动生成了,如下图。3.那我们就可以直接编辑修改文档了,实在是方便了很多。补充一句:按照他们的更新速度,目前也已经支持读取gitlab上java代码了,操作步骤跟读取php的步骤类似,这里就不展开说了,还不知道请回头再看一遍文章hhh。总结如果可以通过扫描代码注释自动生成API文档,写完代码注解后就不用再一条一条的写接口文档,现在又有一个理由可以不再使用swagger了。新增的这个功能可以减轻大部分不必要的工作量,虽然现在只能支持gitlab上的php代码和java代码,但后续肯定还会继续支持更多的平台和编程语言代码,持续使用起来将会更加方便和快捷,希望eolinker能够给我们带来更多的惊喜。官网地址:https://www.eolinker.com

March 26, 2019 · 1 min · jiezi

OAuth2.0: 接入GitHub登录功能

OAuth网络上关于Oauth 2.0协议的基本内容已经很多了,我就不重复写博客了,对基本概念不理解的同学可以先自行Google。但是我发现实际演示的demo很少,所以写了这个偏实战的博客。本文是以GitHub登录为例来演示的。虽然线上环境肯定要有云服务器,但是可以在本地直接模拟调试的不需要写一行代码就可以演示一个完成的登录流程!!请读者务必手动的实际操作!!其实OAuth认证说白了:有三个角色:GitHub,用户,第三方网站third-side需要就是完成一件事:经用户同意,让third-side安全的从GitHub拿到一个tokenthird-side拿到这个token可以用来标识一个用户,读取用户的基本信息代表用户在GitHub上完成一些操作,比如写一个issue之类的基本流程向GitHub申请注册一个application一个application对应一个项目,我们需要拿到一个client id 和 secret来用于后续的登录认证构造相关的登录链接,引导用户点击登录。这一步需要用到上面的client id用户同意登录后,third-side可以拿到一个code(后面详细解释),通过这个code可以向GitHub拿到用户的token第一步注册App因为我们要使用GitHub作为第三方登录,所以肯定要先到官网上注册一个application。网址: https://github.com/settings/d…点击绿色的按钮就行了,点击后会出现????的页面:上面的内容很多,但是只有两个字段是关键的Application Name: 这个是GitHub 用来标识我们的APP的Authorization callback url:就是上面我特意用红色字体标识的的,很关键Homepage url 这个是展示用的,在我们接下来的登录中用不到,随便写就行了这个Authorization callback url就是在用户确认登录后,GitHub会通过这个url来告知我们的服务器。所以真实情况下这个url应该是由专门的服务器程序来监听的。但是这一步大家可以先跟着我填写,后面细细说。完成注册后,我们就有了这些数据:上面有两个数据很关键cliendt_id这是GitHub用来标识我们的APP的接下来我们需要通过这个字段来构建我们的登录urlclient Secret 这个很关键,等会我们就靠它来认证的,要好好保存。我这个只是演示教程,用完就销毁了,所以直接公开了。构造URL然后我们接下来怎么做?很简单<body> <a href=“https://github.com/login/oauth/authorize?client_id=47878c9a96cfc358eb6e”> login with github</a></body>我们只要在我们的登录页面添加这样的代码,引导用户点击我们的登录按钮就行了。注意到上面的流程了吗? 其实我们已经完成了一半的登录认证流程了,然后我们来分析一下。首先请大家思考一下:从用户点击login with github开始,中间有几次重要的HTTP报文传递?不重要是指中间那些网页中附带的对css js资源的请求,这些不算。与登录认证有关的http请求有几个?3个!!!说清楚这一点,基本就明白了。首先我们构造了这样的html页面<body> <a href=“https://github.com/login/oauth/authorize?client_id=47878c9a96cfc358eb6e”> login with github</a></body>关键是我们构造了一个urlhttps://github.com/login/oauth/authorize:这一部分是固定的,只要是用GitHub登录,就得这样。你可以从官方文档上看到这个链接。如果是微信登录,twitter登录,也是大同小异,具体的url可以在相关的官网上找到。GitHub会监听这个路由,来做出登录处理然后后面是一个查询字符串client_id=47878c9a96cfc358eb6e。它的值就是我们之前申请到的client id。这是个必须存在的字段,用户点击登录后,GitHub就是通过这个字段来确认用户究竟是想登录哪个网站。然后GitHub会返回这样的页面,确认用户是否真的要登录,这就是第一次HTTP请求和响应然后用户点击确认后发生了什么?用户点击确认,就是向GitHub发送一个报文,确认自己确实到登录某网站GitHub收到这个用户的确认消息,然后会返回一个状态码为301的报文这个是第二次HTTP请求和响应。因为浏览器收到301重定向后,会直接前往新的网址了,所以你要是没仔细看的话,可能就忽略了。这个状态码为301的报文,它的Location字段大概长这样:https://github.com/fish56/OAuth?code=a1aee8cacf7560825665>https://github.com/fish56/OAuth这个字段就是我们之前填写的callback url,正常情况下这个应该是我们云服务器的网址。但是这里为了演示方便,我这里就随便填写了我的github地址,没关系的code=a1aee8cacf7560825665:(因为笔者中间调试过,所以现在写的token和gif里面的不一样哈)这个就是我们OAuth登录的一个核心信息。我之前说过,我们OAuth登录的核心目的就是让第三方网站能够安全的拿到用户的token。用户的浏览器收到之前的301的HTTP响应后,就会向我们服务器发起请求,请求的同时服务器就拿到了这个code。服务器就可以通过这个code从github拿到用户的token。这就是第三次http请求。然后又有同学可能会问了,为什么要返回一个code,而不是直接返回一个token呢?答:为了安全,如果token经过用户的手里走一遍,就可能会被其他恶意的人窃取。OAuth协议下,GitHub会返回给用户一个code,然后用户浏览器通过重定向携带这个code来访问我们的服务器,这样服务器就拿到了这个code。服务器拿到这个code 之后,通过结合之前的client secret向GitHub申请token,这样会安全一点。之前我们只做了一半, 接下来我们通过postman来演示一下如何通过code拿到token。登录我们要向GitHub申请用户的token,需要code这个只有在用户同意登录后,服务器才能拿到。client secret + client id向https://github.com/login/oauth/access_token发起POST请求,并且携带上面的三个字段这个url是GitHub规定的,你可以在它的官方文档中找到然后我们在postman中构造这样的请求:哎,可以看到,这我们确实拿到了用户的token:access_token=9094eb58a23093fd593d43eb28c1f06ce7904ed5&scope=&token_type=bearer。只不过真实情况下上面的操作都是由线上的服务器完成的,我这样操作是方便大家的理解。代码实战通过上面的例子我们可以看到,如果只是演示,我们是不需要服务器。接下来我们在本地用代码直接演示下。演示的代码使用node + express + request 写的不过代码很简单,不了解上面的技术栈也可以看得懂流程上和之前演示的一模一样,只是通过代码来完成源代码看这里 GitHub因为我们要启动本地的服务器来监听响应,所以我们首先要修改下我们的callback URL。请大家将这个callback URL自行修改为http://localhost:8099/github/login。这是我们程序的目录结构然后这是我们的node代码:const querystring = require(‘querystring’);const express = require(’express’);const request = require(‘request’);const githubConfig = require(’./oauth.conf’)let app = express();// 做一个路由函数,监听/github/login 的get请求app.get(’/github/login’, async function(req,res){ //read code from url let code = req.query.code // 收到code后,向GitHub请求用户的token request.post(githubConfig.access_token_url, { form:{ client_id: githubConfig.client_ID, client_secret: githubConfig.client_Secret, code: code } },function(error, response, body) { //正常情况下,返回值应该是形如access_token=9094eb58a23093fd59 // 3d43eb28c1f06ce7904ed5&scope=&token_type=bearer // 的字符串,可以通过下面的函数来解析 let result = querystring.parse(body) // 拿到token后,返回结果,表示我们成功了 let access_token = result[“access_token”] if(access_token == undefined){ res.send(result.error_description) } res.send(You are login! you token is ${access_token}) })})// 监听 8999 ,启动程序。注意端口号要和我们之前填写的保持一致app.listen(8099,function(){ console.log(’listening localhost:8099’)})这是oauth.conf.js。注意把相关的字段换成你自己的配置。module.exports = { client_ID: ‘47878c9a96cfc358eb6e’, client_Secret: ‘4813689c043c60dbf3d3a0d8e0a984afc0bf810a’, access_token_url: ‘https://github.com/login/oauth/access_token'}这是实际效果我们的代码做了什么事?只是把我们之前的手动使用postman做的事情自动化了监听http://localhost:8099/github/login收到用户浏览器传递的code之后,我们的服务器向GitHub申请了用户token将token返回给用户,表明登录成功不过其实我上面省略了很多操作。正常情况下,服务器拿到用户的token后,应该:把token保存到数据库通过token从github拿到用户的名称之类的数据不应该把token返回给用户返回给用户一个cookie,使得用户保持登录,并且在数据库中把这个cookie和用户的token对应起来总结好了,上面基本就是一次登录流程。构造登录链接,引导用户登录用户登录后,GitHub会把用户重定向到我们预先设置好的URL,同时携带一个code服务器拿到这个code,向GitHub申请token拿到token后,服务器就可以确认用户成功登录了,然后可以返回一个登录成功的页面 ...

March 26, 2019 · 1 min · jiezi

D2 日报 2019年3月20日

???? 新闻➡️ 10%中干去职:腾讯掀起史上最大一轮管理干部裁撤 tech.sina.com.cn???? 开源项目➡️ huyingxi/Synonyms watch 123 star 1760 fork 394 中文近义词工具包 github.com➡️ instantbox/instantbox 非中文 watch 31 star 962 fork 71 在不到 30 秒的时间内得到一个干净、开箱即用的临时 Linux 系统 github.com➡️ t9tio/tomato-pie 非中文 watch 3 star 72 fork 7 番茄工作法的一种新的UI尝试 github.com➡️ openspug/spug 非中文 watch 12 star 274 fork 74 使用 Python+Flask+Vue+Element 组件开发的开源运维管理系统,系统前后端分离,帮助中小型企业完成主机、任务、发布部署、配置文件、监控、报警等管理 github.com➡️ cenfun/puppeteer-chromium-resolver 非中文 watch 1 star 2 fork 1 帮你解决 puppeteer 安装不上的问题 github.com➡️ nbPeterWang/keyboard-key-wordlist watch 0 star 5 fork 1 所有键盘符号的中英文单词表 github.com???? 分享➡️ 使用 Puppeteer 导出声享 PPT mp.weixin.qq.com➡️ 从头到脚撸一个多人视频聊天 — 前端 WebRTC 实战(一) juejin.im➡️ 逐行分析Koa v1 中间件原理 juejin.im➡️ PNG图片压缩原理解析–屌丝的眼泪 juejin.im➡️ Javascript 中最长的关键字序列长什么样子? juejin.im➡️ Vue 的小奇技(第十篇):监听第三方组件的生命周期钩子 juejin.im???? 网站➡️ docsmall 一个免费在线的图片压缩、PDF压缩、PDF合并与分割工具 docsmall.com➡️ Textify.it - Turn Images Into Text 非中文 定义字符来填充图片作画 textify.it☕️ 更优雅地阅读阅读我们精心排版之后的页面 《D2 日报 2019年3月20日》???? 往期回顾您可以访问下面的链接浏览往期内容,或者模糊检索。https://daily.fairyever.com???? 提交分享你的发现和创造 投稿/提交方式???? 如何获取日报➡️ 官方官方网站 ????RSS ????Github | Releases➡️ 微信公众号扫描下方二维码关注“今日前端”公众号,看日报不迷路!????公众号文章版本经过特殊优化,以提高微信环境内的阅读体验。➡️ 社区主页掘金 ????即刻 ????Segmentfault简书开源中国CSDN ...

March 20, 2019 · 1 min · jiezi

git 提交记录回顾总结

说明年前我需要写公司的年度工作总结,所以把项目里的提交日志拉出来查看,其中有几类提交是无效的也是没有意义的,整理起来十分蛋疼,所以记录下来。示例只有操作类型fixadd上面这两个可以知道是修复功能和添加功能,但是需要看代码才能知道修复的是什么,添加的是什么。提交说明使用外文进行说明fix refund英文不好的人可能看到英文得需要想几秒,甚至需要翻译。无详细说明严重BUG修复退货退款时间记录虽然知道是修复严重 BUG,但是 BUG 是什么功能,为什么是严重 BUG 并不知道。而第二种虽然没多大毛病,但改成 “补充遗漏退货退款完成时间” 会更好些。多个功能混在一起提交修改xxx添加xxx去除xxx不建议这样子提交,但是后面回顾代码的时候区分不出每个项对应的内容。不要怕提交条数多,如果需要审阅代码就知道分开提交的好处了。无意义的说明修复 xxx 文件提交记录里会记录当次提交的所有文件,没有说明的意义。使用 GitHub issues 的方式提交fix issues #894这种提交是模仿 GitHub 上的提交方式,它会自动关联上指定的 issues,对直接在 GitHub 上审阅代码时很好用。但是对于完全独立的代码仓库来说,会不知道具体的问题是什么。可以保留这个方式写在说明第二行即可。gogs 也有类似的功能。但对于禅道,这种没有关联的来说,完全没有必要记录上去。总结对提交进行分类统一提交格式过段时间回来查看提交记录还能看明白提交说明,那就代表说明表述上没有问题feat: xxx 功能详细说明:fix: xxx 功能的 xxx 问题详细说明:关联issues:#123del: xxx 功能[的 xxx 方法]详细说明:adjust: xxx 功能[的 xxx]详细说明:[] 为可选项

March 19, 2019 · 1 min · jiezi

D2 日报 2019年3月19日

???? 新闻➡️ iPad mini - Apple Apple 悄悄在官网更新了新的 ipad 产品,其中新 ipad mini 可以使用 Apple Pencil www.apple.com➡️ 大学生利用白条漏洞骗百万 京东金融称已修复 www.cnbeta.com???? 开源项目➡️ XboxYan/NintendoNes watch 2 star 4 fork 1 一个好看的红白机模拟器 github.com➡️ chinanf-boy/tokei-zh watch 1 star 7 fork 0 ????????翻译: <tokei> 代码信息的统计程序 ❤️ 校对 ✅ github.com➡️ chenjiandongx/go-echarts 非中文 watch 16 star 478 fork 35 Golang 代码生成对应的 echarts 可视化图表 github.com➡️ weiwenhao/tree-ql watch 0 star 22 fork 1 tree-ql是一个laravel扩展,通过简单的配置构建出一套极具描述性,可读性,且没有任何冗余的高性能API. github.com???? 分享➡️ ????30 秒了解尾递归和尾递归优化 - 前端和Node学习笔记 segmentfault.com➡️ 做一个好看的红白机模拟器 - XboxYan前端工作站 segmentfault.com➡️ 没有JS的前端:体积更小、速度更快! www.infoq.cn➡️ 华为发布折叠屏官方适配方案 www.infoq.cn➡️ 10分钟精通Ant Design Form表单 www.yuque.com➡️ HTTP Cache 浅析 juejin.im➡️ 寒冬中的前端社招面试 juejin.im➡️ Ant Design 情感化设计 zhuanlan.zhihu.com➡️ ES5 to ESNext — 自 2015 以来 JavaScript 新增的所有新特性 zhuanlan.zhihu.com➡️ 这是不是你们的甲方爸爸?《甲方的要求》 mp.weixin.qq.com???? 网站➡️ Mock - Mockup your videos with devices 给屏幕录像套上手机/设备的外观模型 www.mock.video➡️ Webiny 非中文 基于 GraphQL 和 React 的开源 CMS 系统 www.webiny.com➡️ Vev 非中文 自由的可视化网站构建器 www.producthunt.com➡️ Free online PDF Extractor 非中文 将 pdf 中的图片全部提取出来并打包下载的一个工具,还可以看到文档中纯文字部分 www.extractpdf.com➡️ JavaScript loose comparison (==) step by step 使用这个工具测试 JavaScript 里面的一个弱等于计算 (==) 输出是 true 还是 false,不仅有结果,还会有详细解释 felix-kling.de???? 设计➡️ LandingStock 非中文 可用于落地页的免费图片合集 landingstock.com☕️ 更优雅地阅读阅读我们精心排版之后的页面 《D2 日报 2019年3月19日》???? 往期回顾您可以访问下面的链接浏览往期内容,或者模糊检索。https://daily.fairyever.com???? 提交分享你的发现和创造 投稿/提交方式???? 如何获取日报➡️ 官方官方网站 ????RSS ????Github | Releases➡️ 微信公众号扫描下方二维码关注“今日前端”公众号,看日报不迷路!????公众号文章版本经过特殊优化,以提高微信环境内的阅读体验。➡️ 社区主页掘金 ????即刻 ????Segmentfault简书开源中国CSDN ...

March 19, 2019 · 1 min · jiezi

Pandas之旅(四) : 可能是社区内最实用的Pandas技巧

Pandas不为人知的七大实用技巧大家好,我今天勤快地回来了,这一期主要是和大家分享一些pandas的实用技巧,会在日常生活中大大提升效率,希望可以帮助到大家,还是老样子,先给大家奉上这一期的章节目录:自定义pandas选项,设置实用pandas中testing模块构建测试数据巧用accessor访问器合并其他列拼接DatetimeIndex使用分类数据(Categorical Data)节省时间和空间利用Mapping巧妙实现映射压缩pandas对象源码及GitHub地址好啦,话不多说,让我们一个个看吧1. 自定义pandas选项,设置首先,大家可能不知道,pandas里面有一个方法pd.set_option(),利用它我们可以改变一些pandas中默认的核心设置,从而适应我们自身的需要,开始前还是老样子,让我们先导入numpy和pandas包import numpy as npimport pandas as pdf’Using {pd.name}, Version {pd.version}‘‘Using pandas, Version 0.23.0’现在让我们编写一个start方法来实现自定义pandas设置def start(): options = { ‘display’: { ‘max_columns’: None, ‘max_colwidth’: 25, ’expand_frame_repr’: False, # Don’t wrap to multiple pages ‘max_rows’: 14, ‘max_seq_items’: 50, # Max length of printed sequence ‘precision’: 4, ‘show_dimensions’: False }, ‘mode’: { ‘chained_assignment’: None # Controls SettingWithCopyWarning } } for category, option in options.items(): for op, value in option.items(): pd.set_option(f’{category}.{op}’, value) # Python 3.6+if name == ‘main’: start() del start # Clean up namespace in the interpreter大家可以发现,我们在方法的最后调用了pandas的set_option方法,直接利用我们自定义的参数替代了原有的pandas参数,现在让我们测试一下:pd.get_option(‘display.max_rows’)Out:14可以发现max_rows 已经被替换成了我们设置的14,现在用一个真实的例子,我们利用一组公开的鲍鱼各项指标的数据来实验,数据源来自机器学习平台的公开数据url = (‘https://archive.ics.uci.edu/ml/' ‘machine-learning-databases/abalone/abalone.data’)cols = [‘sex’, ’length’, ‘diam’, ‘height’, ‘weight’, ‘rings’]abalone = pd.read_csv(url, usecols=[0, 1, 2, 3, 4, 8], names=cols)abalone sex length diam height weight rings 0 M 0.455 0.365 0.095 0.5140 15 1 M 0.350 0.265 0.090 0.2255 7 2 F 0.530 0.420 0.135 0.6770 9 3 M 0.440 0.365 0.125 0.5160 10 4 I 0.330 0.255 0.080 0.2050 7 5 I 0.425 0.300 0.095 0.3515 8 6 F 0.530 0.415 0.150 0.7775 20 … … … … … … … 4170 M 0.550 0.430 0.130 0.8395 10 4171 M 0.560 0.430 0.155 0.8675 8 4172 F 0.565 0.450 0.165 0.8870 11 4173 M 0.590 0.440 0.135 0.9660 10 4174 M 0.600 0.475 0.205 1.1760 9 4175 F 0.625 0.485 0.150 1.0945 10 4176 M 0.710 0.555 0.195 1.9485 12 我们可以看到,数据截断为14行,保留了小数点后4位小数作为精度,和我们刚刚设置的precision=4是一样的2. 实用pandas中testing模块构建测试数据通过pandas.util.testing提供的方法,我们可以很容易的通过几行代码就构建出一个简单的测试数据类型,比如我们现在构建一个DataTime类型的数据,时间间隔为月:import pandas.util.testing as tmtm.N, tm.K = 15, 3 # 规定行和列import numpy as npnp.random.seed(444)tm.makeTimeDataFrame(freq=‘M’).head() # 设置时间间隔为月# tm.makeTimeDataFrame(freq=‘D’).head() 设置时间间隔为天 A B C 2000-01-31 0.3574 -0.8804 0.2669 2000-02-29 0.3775 0.1526 -0.4803 2000-03-31 1.3823 0.2503 0.3008 2000-04-30 1.1755 0.0785 -0.1791 2000-05-31 -0.9393 -0.9039 1.1837 瞎生成一组乱七八糟的数据:tm.makeDataFrame().head() A B C nTLGGTiRHF -0.6228 0.6459 0.1251 WPBRn9jtsR -0.3187 -0.8091 1.1501 7B3wWfvuDA -1.9872 -1.0795 0.2987 yJ0BTjehH1 0.8802 0.7403 -1.2154 0luaYUYvy1 -0.9320 1.2912 -0.2907 关于可以随机生成的数据类型, 一共大概有30多种,大家如果感兴趣可以多试试:[i for i in dir(tm) if i.startswith(‘make’)][‘makeBoolIndex’, ‘makeCategoricalIndex’, ‘makeCustomDataframe’, ‘makeCustomIndex’, ‘makeDataFrame’, ‘makeDateIndex’, ‘makeFloatIndex’, ‘makeFloatSeries’, ‘makeIntIndex’, ‘makeIntervalIndex’, ‘makeMissingCustomDataframe’, ‘makeMissingDataframe’, ‘makeMixedDataFrame’, ‘makeMultiIndex’, ‘makeObjectSeries’, ‘makePanel’, ‘makePeriodFrame’, ‘makePeriodIndex’, ‘makePeriodPanel’, ‘makePeriodSeries’, ‘makeRangeIndex’, ‘makeStringIndex’, ‘makeStringSeries’, ‘makeTimeDataFrame’, ‘makeTimeSeries’, ‘makeTimedeltaIndex’, ‘makeUIntIndex’, ‘makeUnicodeIndex’]这样我们如果有测试的需求,会很容易地构建相对应的假数据来测试。3. 巧用accessor访问器accessor(访问器) 具体就是类似getter和setter,当然,Python里面不提倡存在setter和getter方法,但是这样可以便于大家理解,pandas Series类型有3类accessor:pd.Series.accessorsOut:{‘cat’, ‘dt’, ‘str’}.cat用于分类数据,.str用于字符串(对象)数据,.dt用于类似日期时间的数据。让我们从.str开始看:假设现在我们有一些原始的城市/州/ 邮编数据作为Dataframe的一个字段:addr = pd.Series([ ‘Washington, D.C. 20003’, ‘Brooklyn, NY 11211-1755’, ‘Omaha, NE 68154’, ‘Pittsburgh, PA 15211’])addr.str.upper() # 因为字符串方法是矢量化的,这意味着它们在没有显式for循环的情况下对整个数组进行操作0 WASHINGTON, D.C. 200031 BROOKLYN, NY 11211-17552 OMAHA, NE 681543 PITTSBURGH, PA 15211dtype: objectaddr.str.count(r’\d’) # 查看邮编有几位0 51 92 53 5dtype: int64如果我们想把每一行分成城市,州,邮编分开,可以用正则;regex = (r’(?P<city>[A-Za-z ]+), ’ # One or more letters r’(?P<state>[A-Z]{2}) ’ # 2 capital letters r’(?P<zip>\d{5}(?:-\d{4})?)’) # Optional 4-digit extensionaddr.str.replace(’.’, ‘’).str.extract(regex) city state zip 0 Washington DC 20003 1 Brooklyn NY 11211-1755 2 Omaha NE 68154 3 Pittsburgh PA 15211 第二个访问器.dt用于类似日期时间的数据。它其实属于Pandas的DatetimeIndex,如果在Series上调用,它首先转换为DatetimeIndexdaterng = pd.Series(pd.date_range(‘2018’, periods=9, freq=‘Q’)) # 时间间隔为季度daterng0 2018-03-311 2018-06-302 2018-09-303 2018-12-314 2019-03-315 2019-06-306 2019-09-307 2019-12-318 2020-03-31dtype: datetime64[ns]daterng.dt.day_name()0 Saturday1 Saturday2 Sunday3 Monday4 Sunday5 Sunday6 Monday7 Tuesday8 Tuesdaydtype: objectdaterng[daterng.dt.quarter > 2] # 查看2019年第3季度和第4季度2 2018-09-303 2018-12-316 2019-09-307 2019-12-31dtype: datetime64[ns]daterng[daterng.dt.is_year_end] #查看年末的一天3 2018-12-317 2019-12-31dtype: datetime64[ns]最后有关.cat访问器我们会在第5个技巧中提到4. 合并其他列拼接DatetimeIndex现在先让我们构建一个包含时间类型数据的Dataframe:from itertools import productdatecols = [‘year’, ‘month’, ‘day’]df = pd.DataFrame(list(product([2017, 2016], [1, 2], [1, 2, 3])), columns=datecols)df[‘data’] = np.random.randn(len(df))df year month day data 0 2017 1 1 -0.0767 1 2017 1 2 -1.2798 2 2017 1 3 0.4032 3 2017 2 1 1.2377 4 2017 2 2 -0.2060 5 2017 2 3 0.6187 6 2016 1 1 2.3786 7 2016 1 2 -0.4730 8 2016 1 3 -2.1505 9 2016 2 1 -0.6340 10 2016 2 2 0.7964 11 2016 2 3 0.0005 我们可以发现year,month,day是分开的三列,我们如果想要把它们合并为完整的时间并作为df的索引,可以这么做:df.index = pd.to_datetime(df[datecols])df.head() year month day data 2017-01-01 2017 1 1 -0.0767 2017-01-02 2017 1 2 -1.2798 2017-01-03 2017 1 3 0.4032 2017-02-01 2017 2 1 1.2377 2017-02-02 2017 2 2 -0.2060 我们可以扔掉没用的列并把这个df压缩为Series:df = df.drop(datecols, axis=1).squeeze()df.head()2017-01-01 -0.07672017-01-02 -1.27982017-01-03 0.40322017-02-01 1.23772017-02-02 -0.2060Name: data, dtype: float64type(df)pandas.core.series.Seriesdf.index.dtype_str’datetime64[ns]‘5. 使用分类数据(Categorical Data)节省时间和空间刚刚我们在第3个技巧的时候提到了访问器,现在让我们来看最后一个.catpandas中Categorical这个数据类型非常强大,通过类型转换可以让我们节省变量在内存占用的空间,提高运算速度,不过有关具体的pandas加速实战,我会在下一期说,现在让我们来看一个小栗子:colors = pd.Series([ ‘periwinkle’, ‘mint green’, ‘burnt orange’, ‘periwinkle’, ‘burnt orange’, ‘rose’, ‘rose’, ‘mint green’, ‘rose’, ’navy’])import syscolors.apply(sys.getsizeof)0 591 592 613 594 615 536 537 598 539 53dtype: int64我们首先创建了一个Series,填充了各种颜色,接着查看了每个地址对应的颜色所占内存的大小注意这里我们使用sys.getsizeof()来获取占内存大小,但是实际上空格也是占内存的,sys.getsizeof(’’)返回的是49bytes接下来我们想把每种颜色用占内存更少的数字来表示(机器学习种非常常见),这样可以减少占用的内存,首先让我们创建一个mapper字典,给每一种颜色指定一个数字mapper = {v: k for k, v in enumerate(colors.unique())}mapper{‘periwinkle’: 0, ‘mint green’: 1, ‘burnt orange’: 2, ‘rose’: 3, ’navy’: 4}接着我们把刚才的colors数组转化为int类型:# 也可以通过 pd.factorize(colors)[0] 实现as_int = colors.map(mapper)as_int0 01 12 23 04 25 36 37 18 39 4dtype: int64再让我们看一下占用的内存:as_int.apply(sys.getsizeof)0 241 282 283 244 285 286 287 288 289 28dtype: int64现在可以观察到我们的内存占用的空间几乎是之前的一半,其实,刚刚我们做的正是模拟Categorical Data的转化原理。现在让我们直接调用一下:colors.memory_usage(index=False, deep=True)Out:650colors.astype(‘category’).memory_usage(index=False, deep=True)Out: 495大家可能感觉节省的空间并不是非常大对不对? 因为目前我们这个数据根本不是真实场景,我们仅仅把数据容量增加10倍,现在再让我们看看效果:manycolors = colors.repeat(10)len(manycolors) / manycolors.nunique() # Much greater than 2.0x Out:20.0f"Not using category : { manycolors.memory_usage(index=False, deep=True)}"‘Not using category : 6500’f"Using category : { manycolors.astype(‘category’).memory_usage(index=False, deep=True)}"‘Using category : 585’这回内存的占用量差距明显就出来了,现在让我们用.cat来简化一下刚刚的工作:new_colors = colors.astype(‘category’)new_colors0 periwinkle1 mint green2 burnt orange3 periwinkle4 burnt orange5 rose6 rose7 mint green8 rose9 navydtype: categoryCategories (5, object): [burnt orange, mint green, navy, periwinkle, rose]new_colors.cat.categories # 可以使用.cat.categories查看代表的颜色Index([‘burnt orange’, ‘mint green’, ’navy’, ‘periwinkle’, ‘rose’], dtype=‘object’)现在让我们查看把颜色代表的数字:new_colors.cat.codes0 31 12 03 34 05 46 47 18 49 2dtype: int8我们如果不满意顺序也可以从新排序:new_colors.cat.reorder_categories(mapper).cat.codes0 01 12 23 04 25 36 37 18 39 4dtype: int8有关cat其他的方法,我们还是可以通过遍历dir来查看:[i for i in dir(new_colors.cat) if not i.startswith(’’)][‘add_categories’, ‘as_ordered’, ‘as_unordered’, ‘categories’, ‘codes’, ‘ordered’, ‘remove_categories’, ‘remove_unused_categories’, ‘rename_categories’, ‘reorder_categories’, ‘set_categories’]Categorical 数据通常不太灵活,比如我们不能直接在new_colors上新增一个新的颜色,要首先通过.add_categories来添加ccolors.iloc[5] = ‘a new color’—————————————————————————NameError Traceback (most recent call last)<ipython-input-36-1766a795336d> in <module>()—-> 1 ccolors.iloc[5] = ‘a new color’NameError: name ‘ccolors’ is not definednew_colors = new_colors.cat.add_categories([‘a new color’])new_colors.iloc[5] = ‘a new color’ # 不会报错new_colors.values # 成功添加6. 利用Mapping巧妙实现映射假设现在我们有存贮国家的一组数据,和一组用来映射国家所对应的大洲的数据:countries = pd.Series([ ‘United States’, ‘Canada’, ‘Mexico’, ‘Belgium’, ‘United Kingdom’, ‘Thailand’])groups = { ‘North America’: (‘United States’, ‘Canada’, ‘Mexico’, ‘Greenland’), ‘Europe’: (‘France’, ‘Germany’, ‘United Kingdom’, ‘Belgium’)}我们可以通过下面的方法来实现简单的映射:from typing import Anydef membership_map(s: pd.Series, groups: dict, fillvalue: Any=-1) -> pd.Series: # Reverse & expand the dictionary key-value pairs groups = {x: k for k, v in groups.items() for x in v} return s.map(groups).fillna(fillvalue) membership_map(countries, groups, fillvalue=‘other’)很简单对不对,现在让我们看一下最关键的一行代码,groups = {x: k for k, v in groups.items() for x in v},这个是我之前提到过的字典推导式:test = dict(enumerate((‘ab’, ‘cd’, ‘xyz’))){x: k for k, v in test.items() for x in v}7. 压缩pandas对象如果你的pandas版本大于0.21.0,那么都可以直接把pandas用压缩形式写入,常见的类型有gzip, bz2, zip,这里我们直接用刚才鲍鱼的数据集:abalone.to_json(‘df.json.gz’, orient=‘records’,lines=True, compression=‘gzip’) # 压缩为gz类型abalone.to_json(‘df.json’, orient=‘records’, lines=True) #压缩为jsonimport os.pathos.path.getsize(‘df.json’) / os.path.getsize(‘df.json.gz’) #压缩大小差了10倍,还是gz更厉害8. 源码及GitHub地址这一期为大家总结了很多pandas实用的小技巧,希望大家喜欢我把这一期的ipynb文件和py文件放到了Github上,大家如果想要下载可以点击下面的链接:Github仓库地址: https://github.com/yaozeliang/pandas_share这一期就到这里啦,希望大家能够继续支持我,完结,撒花 ...

March 19, 2019 · 5 min · jiezi

优于 swagger 的 java markdown 文档生成框架-01-入门使用

设计初衷节约时间Java 文档一直是一个大问题。很多项目不写文档,即使写文档,对于开发人员来说也是非常痛苦的。不写文档的缺点自不用多少,手动写文档的缺点也显而易见:非常浪费时间,而且会出错。无法保证及时更新。代码已经变了,但是文档还要同步修改。需要强制人来维护这一种一致性。这很难。为什么不是 swagger-uijava 的文档有几类:jdk 自带的 doc 生成。这个以前实践给别人用过,别人用 C#,看到 java 的默认文档感觉很痛苦。就算是我们 java 开发者,也很讨厌看 jdk 的文档。看着不美观,也很累。swagger-ui 是基于 java 注解的文档生成工具。相对而言比较优雅,也非常强大。但是缺点也是有的。开发人员要写 jdk 原来的注释+注解。注解太多,导致写起来也很痛苦,大部分开发者后来还是选择了放弃。那么问题来了?我们怎么办才能尽可能的让开发人员,和文档阅读人员都乐于接受呢?jdk 自带的 doc 就是基于 maven 插件的,本项目也是。区别如下:尽可能的保证和 Java 原生注释一致,让开发者很容易就可以使用。尽可能的信息全面,但是文档简洁。让文档的阅读者享受到等同于手写文档的体验。将信息的获取和生成区分开。方便用户自己定义自己的输出方式。IDOCi-doc 项目简介为 java 项目生成项目文档。基于原生的 java 注释,尽可能的生成简介的文档。用户可以自定义自己的模板,生成自己需要的文档。特性基于 maven 项目生成包含大部分信息的元数据默认支持 markdown 简化文档的生成,支持自定义模板支持用户自定义文档生成器支持用户自定生成文档的类过滤器新特性添加字段类型别名,支持用户自定义快速入门需要jdk1.8+maven 3.x+maven 引入使用 maven 引入当前 idoc 插件。<build> <plugins> <plugin> <groupId>com.github.houbb</groupId> <artifactId>idoc-core</artifactId> <version>0.1.0</version> </plugin> </plugins></build>测试对象的创建为了演示文档,我们创建了一个 Address 对象。package com.github.houbb.idoc.test.model;/** * 地址 * @author binbin.hou * @since 0.0.1 /public class Address { /* * 城市 / private String country; /* * 街道 */ private String street; public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; }}执行插件mvn com.github.houbb:idoc-core:0.0.2:idoc命令行日志信息[INFO] ———————————— Start generate doc[INFO] 共计 【1】 个文件待处理,请耐心等待。进度如下:==================================================================================================== 100%[INFO] Generator doc with docGenerator: com.github.houbb.idoc.core.api.generator.ConsoleDocGenerator[INFO] ———————————— 文档信息如下:[类名] com.github.houbb.idoc.test.model.Address[类信息] {“comment”:“地址”,“docAnnotationList”:[],“docFieldList”:[{“comment”:“城市”,“name”:“country”,“type”:“java.lang.String”},{“comment”:“街道”,“name”:“street”,“type”:“java.lang.String”}],“docMethodList”:[{“docMethodParameterList”:[],“docMethodReturn”:{“fullName”:“java.lang.String”,“name”:“String”,“packageName”:“java.lang”},“docTagList”:[],“exceptionList”:[],“modifiers”:[“public”],“name”:“getCountry”,“seeList”:[],“signature”:“getCountry()”},{“docMethodParameterList”:[{“docAnnotationList”:[],“name”:“country”,“type”:“java.lang.String”}],“docMethodReturn”:{},“docTagList”:[],“exceptionList”:[],“modifiers”:[“public”],“name”:“setCountry”,“seeList”:[],“signature”:“setCountry(country)”},{“docMethodParameterList”:[],“docMethodReturn”:{“fullName”:“java.lang.String”,“name”:“String”,“packageName”:“java.lang”},“docTagList”:[],“exceptionList”:[],“modifiers”:[“public”],“name”:“getStreet”,“seeList”:[],“signature”:“getStreet()”},{“docMethodParameterList”:[{“docAnnotationList”:[],“name”:“street”,“type”:“java.lang.String”}],“docMethodReturn”:{},“docTagList”:[],“exceptionList”:[],“modifiers”:[“public”],“name”:“setStreet”,“seeList”:[],“signature”:“setStreet(street)”}],“docTagList”:[{“lineNum”:5,“name”:“author”,“parameters”:[“binbin.hou”],“value”:“binbin.hou”},{“lineNum”:6,“name”:“since”,“parameters”:[“0.0.1”],“value”:“0.0.1”}],“fullName”:“com.github.houbb.idoc.test.model.Address”,“modifiers”:[“public”],“name”:“Address”,“packageName”:“com.github.houbb.idoc.test.model”}[INFO] ———————————— Finish generate docMarkdown 的生成参考 03-自定义生成文件过滤器效果参见 idoc-test-全部文档.md进一步学习00-项目概览01-设计初衷02-插件的参数配置03-自定义生成文件过滤器04-字段类型别名支持开源地址idoc ...

March 18, 2019 · 1 min · jiezi

D2 日报 2019年3月18日

???? 新闻➡️ jSearch(聚搜) v1.1.0 发布,全新视觉体验 www.oschina.net➡️ 2019数据库趋势报告 www.infoq.cn???? 开源项目➡️ justmd5/pinduoduo-sdk watch 2 star 19 fork 2 拼多多API SDK【拼多多开放平台】 github.com➡️ twhite96/js-dev-reads 非中文 watch 51 star 661 fork 45 JavaScript 开发者的学习资料、书、视频教程、博客文章,知识点覆盖如基础知识:算法和数据结构,主流前段框架:Vue、React 等 github.com➡️ VKSRC/Github-Monitor 非中文 watch 18 star 391 fork 78 一个用于监控 Github 代码仓库的系统,企业可利用该系统及时发现内部代码泄露 github.com➡️ alexfoxy/laxxx at producthunt 非中文 watch 22 star 1292 fork 41 帮助你在滚动页面的时候创建流畅的动画效果 github.com➡️ heyui/heyui 非中文 一个基于 Vue.js 的高质量 UI 组件库 github.com➡️ wuchangming/spy-debugger watch 110 star 3456 fork 467 微信调试,各种WebView样式调试、手机浏览器的页面真机调试。便捷的远程调试手机页面、抓包工具,支持:HTTP/HTTPS,无需USB连接设备 github.com???? 分享➡️ ES10 特性的完整指南 mp.weixin.qq.com➡️ 如何用Phaser实现一个全家福拼图H5 juejin.im➡️ 每日 30 秒之 巧用可视区域 juejin.im➡️ 2019年大前端技术趋势深度解读 mp.weixin.qq.com???? 网站➡️ @kalasoo 掘金站长博客 ming.today➡️ Logo maker 输入你的公司名,slogan,关键字,帮你你设计公司 logo mybrandnewlogo.com☕️ 更优雅地阅读阅读我们精心排版之后的页面 《D2 日报 2019年3月18日》???? 往期回顾您可以访问下面的链接浏览往期内容,或者模糊检索。https://daily.fairyever.com???? 提交分享你的发现和创造 投稿/提交方式???? 如何获取日报➡️ 官方官方网站 ????RSS ????Github | Releases➡️ 微信公众号扫描下方二维码关注“今日前端”公众号,看日报不迷路!????公众号文章版本经过特殊优化,以提高微信环境内的阅读体验。➡️ 社区主页掘金 ????即刻 ????Segmentfault简书开源中国CSDN ...

March 18, 2019 · 1 min · jiezi

Pandas之旅(三)最实用的Merge, Join,Concat方法详解

Merge, Join, Concat大家好,我有回来啦,这周更新的有点慢,主要是因为我更新了个人简历哈哈,如果感兴趣的朋友可以去看看哈:我的主页个人认为还是很漂亮的~,不得不说,很多时候老外的设计能力还是很强。好了,有点扯远了,这一期我想和大家分享的是pandas中最常见的几种方法,这些方法如果你学会了,某种程度上可以很好的替代Excel,这篇文章是pandas之旅的第三篇,主要会从以下几个方面和大家分享我的心得体会:MergeJoinConcat源码及GitHub地址话不多说,让我们开始今天的Pandas之旅吧!1. Merge首先merge的操作非常类似sql里面的join,实现将两个Dataframe根据一些共有的列连接起来,当然,在实际场景中,这些共有列一般是Id,连接方式也丰富多样,可以选择inner(默认),left,right,outer 这几种模式,分别对应的是内连接,左连接,右连接1.1 InnerMerge (内连接)首先让我们简单的创建两个DF,分别为DataFrame1,DataFrame2,他们的公有列是keyimport numpy as npimport pandas as pdfrom pandas import Series, DataFrame# Let’s make a dframedframe1 = DataFrame({‘key’:[‘X’,‘Z’,‘Y’,‘Z’,‘X’,‘X’],‘value_df1’: np.arange(6)})dframe1 key value_df1 0 X 0 1 Z 1 2 Y 2 3 Z 3 4 X 4 5 X 5 #Now lets make another dframedframe2 = DataFrame({‘key’:[‘Q’,‘Y’,‘Z’],‘value_df2’:[1,2,3]})dframe2 key value_df2 0 Q 1 1 Y 2 2 Z 3 我们现在可以简单地使用pd.merge(dframe1,dframe2)来实现Merge功能pd.merge(dframe1,dframe2) key value_df1 value_df2 0 Z 1 3 1 Z 3 3 2 Y 2 2 我们现在需要注意一点,X仅仅是存在于dframe1的key,在dframe2中不存在,因此大家可以发现,当我们调用pd.merge的时候,会自动默认为inner join,我们再换一种方式写一下,大家就明白了:pd.merge(dframe1,dframe2,on=‘key’,how=‘inner’) key value_df1 value_df2 0 Z 1 3 1 Z 3 3 2 Y 2 2 大家可以发现结果是一样的,看到这里,对sql熟悉的朋友们已经有感觉了估计,因为实在是太像了,如果我们不通过on和how来指定想要merge的公有列或者方式,那么pd.merge就会自动寻找到两个DataFrame的相同列并自动默认为inner join,至此,估计大家也可以猜出其他几种模式的merge啦1.2 LeftMerge (左连接)现在同样的,让我们看一下how=‘left’的情况,这是一个左连接pd.merge(dframe1,dframe2,on=‘key’,how=‘left’) key value_df1 value_df2 0 X 0 NaN 1 Z 1 3.0 2 Y 2 2.0 3 Z 3 3.0 4 X 4 NaN 5 X 5 NaN 我们可以看到返回的是dframe1的所有key值对应的结果,如果在dframe2中不存在,显示为Nan空值1.3 RightMerge (右连接)右连接的原理和左连接正相反pd.merge(dframe1,dframe2,on=‘key’,how=‘right’) key value_df1 value_df2 0 Z 1.0 3 1 Z 3.0 3 2 Y 2.0 2 3 Q NaN 1 这里Q只存在于drame2的key中1.4 OuterMerge (全连接)#Choosing the “outer” method selects the union of both keyspd.merge(dframe1,dframe2,on=‘key’,how=‘outer’) key value_df1 value_df2 0 X 0.0 NaN 1 X 4.0 NaN 2 X 5.0 NaN 3 Z 1.0 3.0 4 Z 3.0 3.0 5 Y 2.0 2.0 6 Q NaN 1.0 这里就是一个并集的形式啦,其实就是一个union的结果,会把key这一列在两个Dataframe出现的所有值全部显示出来,如果有空值显示为Nan1.5 MultipleKey Merge (基于多个key上的merge)刚才我们都是仅仅实现的在一个key上的merge,当然我们也可以实现基于多个keys的merge# Dframe on leftdf_left = DataFrame({‘key1’: [‘SF’, ‘SF’, ‘LA’], ‘key2’: [‘one’, ’two’, ‘one’], ’left_data’: [10,20,30]})df_left key1 key2 left_data 0 SF one 10 1 SF two 20 2 LA one 30 #Dframe on rightdf_right = DataFrame({‘key1’: [‘SF’, ‘SF’, ‘LA’, ‘LA’], ‘key2’: [‘one’, ‘one’, ‘one’, ’two’], ‘right_data’: [40,50,60,70]})df_right key1 key2 right_data 0 SF one 40 1 SF one 50 2 LA one 60 3 LA two 70 这是内连接(交集)的结果#Merge, Innerpd.merge(df_left, df_right, on=[‘key1’, ‘key2’]) key1 key2 left_data right_data 0 SF one 10 40 1 SF one 10 50 2 LA one 30 60 这是外连接(并集)的结果#Merge, Outerpd.merge(df_left, df_right, on=[‘key1’, ‘key2’],how=‘outer’) key1 key2 left_data right_data 0 SF one 10.0 40.0 1 SF one 10.0 50.0 2 SF two 20.0 NaN 3 LA one 30.0 60.0 4 LA two NaN 70.0 这里还有一个地方非常有意思,大家可以发现现在df_left,df_right作为key的两列分别是key1和key2,它们的名字是相同的,刚刚我们是通过制定on=[‘key1’, ‘key2’],那如果我们只指定一列会怎么样呢?pd.merge(df_left,df_right,on=‘key1’) key1 key2_x left_data key2_y right_data 0 SF one 10 one 40 1 SF one 10 one 50 2 SF two 20 one 40 3 SF two 20 one 50 4 LA one 30 one 60 5 LA one 30 two 70 大家可以看到pandas自动把key2这一列拆分成了key2_x和key2_y,都会显示在最后的merge结果里,如果我们想要给这两列重新命名,也是很容易的:# We can also specify what the suffix becomespd.merge(df_left,df_right, on=‘key1’,suffixes=(’_lefty’,’_righty’)) key1 key2_lefty left_data key2_righty right_data 0 SF one 10 one 40 1 SF one 10 one 50 2 SF two 20 one 40 3 SF two 20 one 50 4 LA one 30 one 60 5 LA one 30 two 70 像这样,我们可以通过suffixes参数来指定拆分的列的名字。1.6 Merge on Index (基于index上的merge)我们还可以实现几个Dataframe基于Index的merge,还是老样子,先让我们创建两个Dataframedf_left = DataFrame({‘key’: [‘X’,‘Y’,‘Z’,‘X’,‘Y’], ‘data’: range(5)})df_right = DataFrame({‘group_data’: [10, 20]}, index=[‘X’, ‘Y’])df_left key data 0 X 0 1 Y 1 2 Z 2 3 X 3 4 Y 4 df_right group_data X 10 Y 20 好了,现在我们想要实现两个Dataframe的merge,但是条件是通过df_left的Key和df_right的Indexpd.merge(df_left,df_right,left_on=‘key’,right_index=True) key data group_data 0 X 0 10 3 X 3 10 1 Y 1 20 4 Y 4 20 这样我们也可以得到结果。# We can also get a union by using outerpd.merge(df_left,df_right,left_on=‘key’,right_index=True,how=‘outer’) key data group_data 0 X 0 10.0 3 X 3 10.0 1 Y 1 20.0 4 Y 4 20.0 2 Z 2 NaN 其他的merge方式就类似啦,这里就不一一说了,只是举一个outer join的例子# 通过outer实现外连接,union并集pd.merge(df_left,df_right,left_on=‘key’,right_index=True,how=‘outer’) key data group_data 0 X 0 10.0 3 X 3 10.0 1 Y 1 20.0 4 Y 4 20.0 2 Z 2 NaN 我们也可以尝试一些有意思的merge,比如,如果一个dataframe的index是多层嵌套的情况:df_left_hr = DataFrame({‘key1’: [‘SF’,‘SF’,‘SF’,‘LA’,‘LA’], ‘key2’: [10, 20, 30, 20, 30], ‘data_set’: np.arange(5.)})df_right_hr = DataFrame(np.arange(10).reshape((5, 2)), index=[[‘LA’,‘LA’,‘SF’,‘SF’,‘SF’], [20, 10, 10, 10, 20]], columns=[‘col_1’, ‘col_2’])df_left_hr key1 key2 data_set 0 SF 10 0.0 1 SF 20 1.0 2 SF 30 2.0 3 LA 20 3.0 4 LA 30 4.0 df_right_hr col_1 col_2 LA 20 0 1 10 2 3 SF 10 4 5 10 6 7 20 8 9 现在我们穿建了两个Dataframe 分别是df_left_hr和df_right_hr(Index两层),如果我们想通过使用df_left_hr的key1,key2 及df_right_hr的Index作为merge的列,也是没有问题的# Now we can merge the left by using keys and the right by its indexpd.merge(df_left_hr,df_right_hr,left_on=[‘key1’,‘key2’],right_index=True) key1 key2 data_set col_1 col_2 0 SF 10 0.0 4 5 0 SF 10 0.0 6 7 1 SF 20 1.0 8 9 3 LA 20 3.0 0 1 基本到这里,我已经和大家分享了基础的Merge有关的所有操作,如果你平时生活工作中经常使用Excel执行类似操作的话,可以学习一下Merge哈,它会大幅度减轻你的工作强度的!2.Join现在我们可以接着来看join相关的操作,先让我们看一个小例子left = pd.DataFrame({‘A’: [‘A0’, ‘A1’, ‘A2’, ‘A3’], ‘B’: [‘B0’, ‘B1’, ‘B2’, ‘B3’]}, index = [‘K0’, ‘K1’, ‘K2’, ‘K3’]) right = pd.DataFrame({‘C’: [‘C0’, ‘C1’, ‘C2’, ‘C3’], ‘D’: [‘D0’, ‘D1’, ‘D2’, ‘D3’]}, index = [‘K0’, ‘K1’, ‘K2’, ‘K3’]) left A B K0 A0 B0 K1 A1 B1 K2 A2 B2 K3 A3 B3 right C D K0 C0 D0 K1 C1 D1 K2 C2 D2 K3 C3 D3 left.join(right) A B C D K0 A0 B0 C0 D0 K1 A1 B1 C1 D1 K2 A2 B2 C2 D2 K3 A3 B3 C3 D3 其实通过这一个小例子大家也就明白了,join无非就是合并,默认是横向,还有一个点需要注意的是,我们其实可以通过join实现和merge一样的效果,但是为了避免混淆,我不会多举其他的例子了,因为我个人认为一般情况下还是用merge函数好一些3. Concat为了更加全面彻底地了解Concat函数,大家可以先从一维的Numpy Array开始,首先让我们简单的创建一个矩阵:# Create a matrix arr1 = np.arange(9).reshape((3,3))arr1array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])接着让我们通过concatenate函数进行横向拼接:np.concatenate([arr1,arr1],axis=1)array([[0, 1, 2, 0, 1, 2], [3, 4, 5, 3, 4, 5], [6, 7, 8, 6, 7, 8]])再让我们进行纵向拼接:# Let’s see other axis optionsnp.concatenate([arr1,arr1],axis=0)array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 1, 2], [3, 4, 5], [6, 7, 8]])有了基础的印象之后,现在让我们看看在pandas中是如何操作的:# Lets create two Series with no overlapser1 = Series([0,1,2],index=[‘T’,‘U’,‘V’])ser2 = Series([3,4],index=[‘X’,‘Y’])#Now let use concat (default is axis=0)pd.concat([ser1,ser2])T 0U 1V 2X 3Y 4dtype: int64在上面的例子中,我们分别创建了两个没有重复Index的Series,然后用concat默认的把它们合并在一起,这时生成的依然是Series类型,如果我们把axis换成1,那生成的就是Dataframe,像下面一样pd.concat([ser1,ser2],axis=1,sort =True) # sort=Ture是默认的,pandas总是默认index排序 0 1 T 0.0 NaN U 1.0 NaN V 2.0 NaN X NaN 3.0 Y NaN 4.0 我们还可以指定在哪些index上进行concat:pd.concat([ser1,ser2],axis=1,join_axes=[[‘U’,‘V’,‘Y’]]) 0 1 U 1.0 NaN V 2.0 NaN Y NaN 4.0 也可以给不同组的index加一层标签pd.concat([ser1,ser2],keys=[‘cat1’,‘cat2’])cat1 T 0 U 1 V 2cat2 X 3 Y 4dtype: int64如果把axis换成是1,那么keys就会变成column的名字:pd.concat([ser1,ser2],axis=1,keys=[‘cat1’,‘cat2’],sort=True) cat1 cat2 T 0.0 NaN U 1.0 NaN V 2.0 NaN X NaN 3.0 Y NaN 4.0 如果是两个现成的dataframe直接进行concat也是一样:dframe1 = DataFrame(np.random.randn(4,3), columns=[‘X’, ‘Y’, ‘Z’])dframe2 = DataFrame(np.random.randn(3, 3), columns=[‘Y’, ‘Q’, ‘X’])dframe1 X Y Z 0 1.119976 -0.853960 0.027451 1 -0.536831 0.982092 -0.157650 2 -0.219322 -1.489809 1.607735 3 0.767249 -1.661912 0.038837 dframe2 Y Q X 0 -0.035560 0.875282 -1.630508 1 -0.439484 0.096247 1.335693 2 0.746299 0.568684 1.197015 #如果没有对应的值,默认为NaN, 空值pd.concat([dframe1,dframe2],sort=True) Q X Y Z 0 NaN 1.119976 -0.853960 0.027451 1 NaN -0.536831 0.982092 -0.157650 2 NaN -0.219322 -1.489809 1.607735 3 NaN 0.767249 -1.661912 0.038837 0 0.875282 -1.630508 -0.035560 NaN 1 0.096247 1.335693 -0.439484 NaN 2 0.568684 1.197015 0.746299 NaN 4. 源码及Github地址今天我为大家主要总结了pandas中非常常见的三种方法:mergeconcatjoin大家可以根据自己的实际需要来决定使用哪一种我把这一期的ipynb文件和py文件放到了Github上,大家如果想要下载可以点击下面的链接:Github仓库地址: https://github.com/yaozeliang/pandas_share这一期就到这里啦,希望大家能够继续支持我,完结,撒花 ...

March 17, 2019 · 5 min · jiezi

Java到底要做到什么程度才能适应市场的需求(本人的面试经历)

前言:从过年前就萌生出要跳槽的想法,到过年来公司从月初提出离职到~~号正式离职,上班的时间也出去面试过几家公司,后来总觉的在职找工作总是得请假,便决心离职后找工作。到3月10号找到了一家互联网公司成功应聘上,中间也经历了很多公司,有外包的、创业的、互联网的等等各种类型,也收到了很多offer,也有面试不顺序的…今天来记录一下自己面试中的问题,围绕着java到底应该具备什么样的水平才能适应现在市场的要求的主题来谈一谈。本篇文章目录:一:面试中的问题二: 面试中要注意的问题三:关于最后的选择四:两年java到底应该具备什么样的水平一:面试中的问题java集合框架:1:介绍一下java的集合框架2:HashMap遇见哈希冲突会如何怎么办?HashMap是线程安全的吗?HashMap在高并发下会有什么问题?然后引入ConcurrentHashMap的原理?3:Hahtable和concurrentHashMap的区别?4:数组和ArrayList的区别?Arraylist是如何扩容的?5:线程池中的阻塞队列一般会选择哪种队列?为什么?6:RetreenLock的原理?AQS的原理?7:HashMap的容量为什么推荐是2的幂次方?框架类:1:mybatis的二级缓存有什么问题?2:mybaits中的mapper的#{}和${}有什么区别?哪种可以防止sql注入?2:我们知道mybatis的mapper和接口之间是没有对象的,那么它是如何映射的?4:说说springmvc的注解有哪些?他们的原理是什么?5:springmvc的控制器是单例的吗?是线程安全的吗?6:struts1和struts2的区别?是线程安全的吗?7:spring如何解析它的xml文件?8:spring的核心是什么?Aop的原理是什么?redis相关:1:redis数据类型有哪些?2:zset数据类型是如何排序的?3:redis如何做项目的中间缓存层?4:redis的Hash的时间复杂度是多少?数据库:1:数据库索引分为哪几种?组合索引有什么要注意的问题?2:什么是悲观锁 什么是乐观锁?如何实现悲观锁?3: 数据库关键字的执行顺序是什么?4:如何进行sql优化?5:有没有进行过分库分表操作?分库之后如何保持事务一致?分布式和微服务:1:微服务要克服那些问题?微服务系统是怎样通信的?2:分布式环境下如何解决session不一致的问题?3:分布式下如何保证id一致?4:你在dubbo的使用过程中遇到什么问题?5: zookeeper的负载均衡算法有哪些?jdk源码相关1:synchronized的原理?它该怎么用?如何一个方法是synchronized的,其他的非synchronzied线程能进入吗?2:cvs中的ABA问题如何解决?3:volatile的原理是什么?volatile一定是线程安全的吗?4:ThreadLocal是什么?它的原理是什么?5:CountDowanLatch有没有用过?适合在什么样的场景下用?设计模式相关:1:实现两种单例模式2:讲一下观察者模式3:spring中都用到哪些设计模式?4:动态代理模式是如何实现的?5:你在项目中用到哪些设计模式了?讲解一下业务场景算法相关:1:快速排序的时间复杂度?手写快速排序(注意递归式和非递归式的实现方式)2:手写二分查找3:手写堆排序4:一个int数组如何进行奇数和偶数分离?5:用算法实现String转doublejvm相关:1: jvm的垃圾回收算法有哪些?分别解释一下?2: 新生代为什么要设置两个survior区?3:如何通过一个.class文件获取它的jdk版本?4:jvm的内存模型?哪些是线程私有的?哪些是公共的?关于自己的项目(问的时间最长)1:简述一下自己的项目?你在其中主要是做什么的?2:你在项目中都遇到了哪些难题?最后都是怎么解决的?3:项目有多大规模?周期多久(这个很多都问到的)4:讲一下某一模块的具体实现方式?然后从中挑刺5:如何解决某一时刻的高并发请求?6:如何解决订单支付回调的超时问题?轮询应该怎么写?其他:1:秒杀场景如何削峰?2:http和udp的区别是什么?3:ajax的跨域问题4:nio与io的区别?什么情况下适合用nio5: 说说常见的linux命令,linux查看内存的命令是什么?7:git遇见代码冲突了怎么办?8:说几个常见的maven命令,maven如何排除一个jar包的冲突?二: 面试中要注意的问题2.1:一定要有自己的实际项目经验按照我这么多面试经验?其实有的公司会侧重于问自己做的项目经验,有的公司侧重于问问题,一般互联网公司会对技术要求比较高,既要求项目经验又要要求技术水平2.2:可以适当渲染,但是不要夸大其词面试的过程中最忌讳的就是夸夸其谈,高屋建瓴很厉害,但是一到实际细节都不知所云了,在技术总监面前,其实你吹牛或者是真的会他是一目了然的。不懂装懂,有的面试官又给你台阶下,不然你就卡带了,这很容易造成面试的不好印象2.3:要会自我介绍面试的时候一般的话都会让你做一个自我介绍,这个要分对象,是技术官还是Hr,如果是技术官侧重于综述一下自己的项目的实际技术栈和技术路线,如果是Hr的话不要用过多的技术语言,而要说一些自己的实际工作经历或者自己上家公司的运营情况2.4:关于简历简历切记不可太啰嗦,但是不可太简单,作为技术的简历一般起码得在3页,不然HR会觉得你的求职态度不怎么好,不管如何求职结果如何,一个良好的简历会给人留下好的第一印象(有简历模板)三:关于最后的选择说实话也接受到很多HR的offer邀请,但是我一般会选择说考虑一下一天以后再给回复,切不可直接把话说死,不然后面就尴尬了。实际提供的offer的有一家外包公司,三家创业公司,两家互联网公司,最终选择了一家互联网公司,虽然实际上班地点有点远(下了地铁还得座公交,后来还是选择骑单车了),但是互联网公司会给你快的成长速度,并且互联网技术栈都比较新..相比于传统企业会有更多的技术挑战。而外包公司的话,可能环境不怎么好,我记得自己当初还是个小白的时候,去了外包,那里的优点就是会有不断的活,新人进去的话收获还是挺多的,但是作为已经有两年经验的我,外包很显然不适合我的后期职业发展。缺点:技术更新迭代的太慢,没有归属感,最后的选择我个人的意见是选择技术优先,毕竟以后软件路还长,技术才是王道四:两年java到底应该具备什么样的水平两年java的面试过程中遇到了很多挑战,也遇到了一些不谈技术的公司,从上面的面试题可以看出,目前对于java的要求越来越高,水涨船高,毕竟这个行业的人数越来越多,而保持自己的竞争力的唯一方法就是找对方向,不断学习,注意这里我提到的第一点是方向,然后才是学习。给自己制定一个职业规划,按照这个路线往前走,我其实还在想分布式微服务这块以后再深入学习,可是按照市场要求,现在已经刻不容缓了,一些技术架构比如:springcloud、duboo都得保持学习,这样才能有竞争力!作为一名两年的javaSir,你必须具备以下技能1:阅读源码的能力,多用Intelj idea这个开发工具,而不是eclipse。它是直接支持反编译class文件的,多读jdk源码,吸收优秀的源码并加以复用2:做到能够手写常见的排序算法,比如快速排序和堆排序、冒泡排序、选择排序、二分查找这些都是必须的3:对java的框架有很深入的认识,现在基本流行的ssm框架很多人都会,可是知道一些原理的人就不多了,得不断研究这些框架本身,它们都是经过无数次锤炼 出来的优秀框架4:多用redismongodb,传统的关系型数据库已经无法市场需求了,这些东西也是面试中的一部分,虽不是重点,但也是加分的选项5:对于微服务和分布式,这个是有一定难度的,我在面试人人车的时候,一面很顺利,二面被技术总监给pass了,问题就是分布式不是特别熟悉!要想进入好的互联网公司,分布式和微服务是很必须的6:jvm的底层,这里要推荐的书就是周志明的《深入jvm虚拟机》这本书了,我总在闲暇时间读它,所以jvm的问题还是信手拈来的最后送上福利:腾讯课堂的的Java工程化、高性能及分布式、高性能、高架构、性能调优、Spring、MyBatis、Netty源码分析视频、java高并发处理视频(在腾讯买得花1800块左右)如果有谁想要,可以私信我,免费分享哦,我花了些钱买的

March 17, 2019 · 1 min · jiezi

只因数据过滤,方可模拟beanutils框架

导读上一篇文章已经详细介绍了框架与RTTI的关系,RTTI与反射之间的关系。其中详细介绍了框架与反射的关系,这也是很多培训机构把反射作为高级教程来讲解。其实,我工作年限也不长,大概八九个月吧。但我见过很多技术人员,而我喜欢与别人讨论技术。从中也知道了,很多公司没有实现数据过滤。什么是数据过滤?比如客户端向服务器端发送展示项目图片的请求,服务端接收到前端的请求并从数据库中拿到项目图片的对象,我们只要返回图片的在服务端的地址和名称即可,没必要将整个图片对象返回给客户端,因为,那样将会造成数据的冗余。因而,我们这时需要过滤数据(对象),如代码所示:/** * 常用的把图片转成 {id: 1, path: “xxx”}结构 /public static JSONObject img2Json(Picture picture) { if (isNotNull(picture)) { String[] PICTURE_JSON = {“id”, “remoteRelativeUrl:path”}; JSONObject jsonObject = propsFilter(picture, PICTURE_JSON); return jsonObject; } else { return null; }}如上诉代码的转换,公司使用的是commons-beanutils这个框架。我们只要在项目中农添加其maven配置即可: <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.2</version> </dependency>我个人比较喜欢研究源码,于是,仿照这个框架写了自己的框架,下面,就是介绍我个人的框架。我的beanutils框架框架使用的算法或技术递归算法。我们并不推荐使用递归,因为,方法自调用自己。根据JVM的内部原理,每个方法都是一个方法栈。而栈是存放数据的一种结构,其采用FIFO(First In Last Out),即先进后出。和我们堆放菜盘一样,先垒的最后拿出来。既然是数据存储,肯定会超出容量,因为,内存不是无限大的,恰如水满自溢。但是,我们在这里还是使用递归,因为,在深度调用算法当中,采用递归是合适的。java的反射机制。我们根据Javabean的属性名称获取值。核心算法说明。如果javabean的对象属性类型不是用户自定义的类型,我们根据反射调用get方法拿到属性的值如果javabean的对象属性类型是用户自定义的类型,我们利用递归重新调用改方法,直到出现遇见上面的条件 /* * Created By zby on 20:28 2019/2/13 * * @param bean 实体对象 * @param props 属性名称 / public static Object getProperty(Object bean, String props) { if (bean == null) throw new RuntimeException(“实例化对象不存在bean=” + bean); if (StringHelper.isBlank(props)) throw new RuntimeException(“属性名称不存在props=” + props); Class<?> clazz = null; String methodName = null; String fieldName = null; String typeName = null; try { clazz = bean.getClass(); if (props.indexOf(".") != -1) { methodName = MethodHelper.propsToGetMethod(props.substring(0, props.indexOf("."))); Method method = clazz.getDeclaredMethod(methodName); Object obj = method.invoke(bean); return getProperty(obj, props.substring(props.indexOf(".") + 1)); } Field field = clazz.getDeclaredField(props); typeName = field.getType().getName(); if (typeName.equalsIgnoreCase(“boolean”)) { field.setAccessible(true); return field.getBoolean(bean); } methodName = MethodHelper.propsToGetMethod(props); Method method = clazz.getDeclaredMethod(methodName); return method.invoke(bean); } catch (NoSuchMethodException e) { logger.error(clazz + “类型没有” + methodName + “方法”); e.printStackTrace(); } catch (NoSuchFieldException e) { logger.error(clazz + “类型没有” + fieldName + “属性”); e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; }如何使用上诉算法我们既然是通过属性名称来获取属性对象。我们可以设计一个算法,算法该算法有两个参数,一个是当前对象,一个是对象的属性数组。属性数组还可以有别名。为什么需要别名?比如当前对象采用组合关系,使用自定义的类。比如说订单类使用用户类(User)的对象作为属性,我们在订单中希望看到用户姓名,我们可以这样调用user.name,以该字段传给客户端,但客户端需要转换才能拿到用户名,因而,我们需要一个别名,前端不用转换,就可以拿到用户名,比如:user.name:username。当然,我们需要将对象转化为json格式的框架, 这里使用的阿里巴巴的fastjson框架,我们可以在项目中配置maven: <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.28</version></dependency>所示,算法设计为: /* * Created By zby on 9:40 2019/2/13 * 模拟框架中的数据 * * @param object 参数对象 * @param props String类型的变长数组,比如{“id:projectId”, “mobile”,…} * 前半部分是javabean的属性名,后半部分是返回到给客户端的参数名 */public static JSONObject propsFilter(Object object, String… props) { //【1】判断对象和变长数组的是否为空,以及变长数组的长度是否为0 boolean isNull = object == null || (null == props && props.length == 0); if (isNull) { logger.warn(“参数为空object=” + object + “props=” + props); return null; } JSONObject jsonObject = new JSONObject(); for (String prop : props) { //【2】再判断对象不为空,或者长度不为0 if (prop == null && prop.length() == 0) { logger.warn(“参数为空prop= " + prop); throw new RuntimeException(“参数为空prop=” + prop); } Object o = null; String[] namePair = StringUtils.split(prop, “:”); try { o = PropertyUtil.getProperty(object, namePair[0]); } catch (Exception e) { logger.warn(“类” + object.getClass() + “,属性” + namePair[0] + “不存在”); } String key = namePair.length <= 1 ? namePair[0] : namePair[1]; if (o instanceof Date) jsonObject.put(key, DateUtil.simpleFormate((Date) o)); else if (o instanceof BigDecimal) jsonObject.put(key, CommonUtil.toFiexd((BigDecimal) o, 2)); else if (o instanceof TitleEnum) jsonObject.put(key, CommonUtil.builderEnum((TitleEnum) o)); else jsonObject.put(key, o); } return jsonObject;}测试框架和类我们既然写好了这个框,也使用了这个框架,因而,我们可以使用Junit来测试: @Test public void test(){ Address address = new Address(); address.setAddressTag(AddressTagEnum.ADDRESS_TAG_COMPANY); address.setArea(“杭州市….”); address.setConsignee(“zby”); User user = new User(); user.setHobby(HobbyEnum.HOBBY_DANCING); user.setGender(“男”); user.setUserName(“蒋三”); OrderSnapshot orderSnapshot = new OrderSnapshot(); orderSnapshot.setAddress(address); orderSnapshot.setId(1L); orderSnapshot.setName(“复读机”); orderSnapshot.setOrderNo(Long.valueOf(System.currentTimeMillis()).toString() + “1L”); orderSnapshot.setUser(user); String[] json = {“address.consignee:consignee”,“user.hobby:hobby”, “address.addressTag:addressTag”, “address.area:area” ,“address.consignee:consignee”,“user.userName:userName”}; System.out.println(JsonUtil.propsFilter(orderSnapshot, json));测试结果为:可见,我们算法时成功的。总结我们还是要时常看源码,因为,你的目的不是写出框架,而是看别人写框架的思想。毕竟,思想主导一切行为,行为成就一个的未来。致努力的自己。 ...

March 17, 2019 · 2 min · jiezi

Python进阶:如何将字符串常量转化为变量?

前几天,我们Python猫交流学习群 里的 M 同学提了个问题。这个问题挺有意思,经初次讨论,我们认为它无解。然而,我认为它很有价值,应该继续思考怎么解决,所以就在私密的知识星球上记录了下来。万万没想到的是,在第二天,有两位同学接连给出了解决方法!由此,群内出现了一轮热烈的技术交流。本文将相关的内容要点作了梳理,并由此引申到更进一步的学习话题,希望对你有所帮助。1、如何动态生成变量名?M 同学的问题如下:打扰一下大家,请教一个问题,已知 list = [‘A’, ‘B’, ‘C’, ‘D’] , 如何才能得到以 list 中元素命名的新列表 A = [], B = [], C = [], D = [] 呢?简单理解,这个问题的意思是,将字符串内容作为其它对象的变量名。 list 中的元素是字符串,此处的 ‘A’-‘D’ 是常量 ,而在要求的结果中,A-D 是变量 。如果强行直接将常量当做变量使用,它会报错:>>> ‘A’ = []…SyntaxError: can’t assign to literal报错中的literal 指的是字面量 ,这是计算机科学中常见的一个概念,用于表达源代码中的固定值。 例如,整数、浮点数、字符串等基本类型,就是字面量。字面量指的就是一个量本身,可以理解为一种原子性的实体,当然不能再被赋值了。所以,取出的字符串内容,并不能直接用作变量名,需要另想办法。有初学者可能会想,list[0] = [] 行不行?当然不行,因为没有出现 A 。那 A = list[0] ,接着 A = [] 呢?那也不行,因为这里的 A 是你凭空定义出来的,而不是从已有条件中生成的。当时,群里只有两三个同学参与了讨论,我们没想到解决办法。但是,我觉得这个题目很有意思,值得玩味。因为,如果能解决这个问题,那就意味着可以不作预先定义,而是动态地生成变量名,这不仅能减少给变量取名的麻烦,还实现了自动编码!可以设想一下未来,人工智能在编写代码的时候,如果能根据已知条件,动态生成变量名,那编写代码的过程不就顺利多了么?(据说,现在已经有人工智能可以编写代码了,不知它在取变量名时,是用的什么方法?)2、办法总是有的最近,学习群里蒙混进来了几个打广告的,为此,我决定提高审核门槛,例如,用群里的问题来作个考核。万万没想到的是,第一个被考核到的 Q 同学,几乎不假思索地就说出了一个解决上述问题的思路。而偏偏就是那么巧 ,几乎在同时,群内的 J 同学给出了另外一个解决方法(他没看到群内的讨论,而是看到了知识星球的记录,才知道这个问题的)。也就是说,前一晚还以为无解的问题,在第二天竟得到了两种不同的解决方法!那么,他们的答案是什么呢?# J 同学的解答>>> list1 = [‘A’, ‘B’, ‘C’, ‘D’]>>> for i in list1:>>> globals()[i] = []>>> A[]这个方法通过修改全局命名空间,巧妙地“定义”出了新的变量。globals() 方法取出来的是一个字典,字符串 ‘A’ 是其中一个键值(key),而这个键值恰恰是全局命名空间中的一个变量,这就实现了从常量到变量的转化。在数据结构层面上,空列表 [] 作为一个值(value)跟它的字符串键值绑定在一起,而在运用层面上,它作为变量内容而跟变量名绑定在一起。看到这个回答的时候,我就突然想起来了,上个月转载过一篇《Python 动态赋值的陷阱》,讲的正是动态地进行变量赋值 的问题啊!我似乎只关注了 globals() 与 locals() 用法的区别,却没有真正地掌握它们的原初用途。J 同学说,他正是看了那篇文章,才学得了这个方法。这就有意思了,我分享了一个自己囫囵吞枣的知识,然后它被 J 同学吸收掌握,最后反馈回来解决了我的难题。我真切地感受到了知识分享的魅力:知识在流动中获得生命,在碰撞中锃亮色泽。 同时,我也真切地明白了一个互助的学习团体的好处:利人者也利己,互助者共同进步。3、动态执行代码的方法新进群的 Q 同学,提供了一个不同的答案:# Q 同学的解答>>> list1 = [‘A’, ‘B’, ‘C’, ‘D’]>>> for i in list1:>>> exec(f"{i} = []")>>> A[]他的写法用到了 Python 3.6 才引入的 f-strings 特性,事实上,在较低版本中,也是可以实现的,只需要保证 exec() 方法接收的参数是包含了变量 i 的字符串即可,例如这样写:# 以下代码可替换上例的第 4 行exec(i + " = []")# 或者:exec("{} = []".format(i))# 或者:exec(’ ‘.join([i, ‘= []’]))这几种写法的区别只是字符串拼接法的区别,关于如何拼接字符串,以及不同方法之间的区别,可参看《详解Python拼接字符串的七种方式》。Q 同学这个答案的核心在于 exec() 方法,它是内置的,用途是执行储存在字符串或文件中的代码段。 它的基础用法如下:>>> exec(‘x = 1 + 2’)>>> x3# 执行代码段>>> s = “”">>> x = 10>>> y = 20>>> sum = x + y>>> print(sum)>>> “”">>> exec(s)30看完了 exec() 的用法,我们再回来看 Q 同学的答案。for-循环中取出来的 i 是字符串,而拼接后的字符串经过 exec() 的处理,就获得了动态编写代码的效果。也就是说,因为字符串常量的内容被当做有效代码而执行了,其中的 ‘A’-‘D’ 元素,就取得了新的身份,变成了最终的 A-D 变量名。这个方法看起来很简单啊,可是由于 exec() 方法太生僻了,直到 Q 同学提出,我们才醒悟过来。注意:在 Python3 中,exec() 是个内置方法;而在 Python2 中,exec 是个语句(statement),另外有个 execfile() 方法,两者相合并,就成了 Python3 中的 exec() 方法。本文使用的是 Python3。4、总结抽象一下最初的问题,它实际问的是“如何将字符串内容作为其它对象的变量名”,更进一步地讲是——“如何将常量转化为变量 ”。使用直接进行赋值的静态方法,行不通。两位同学提出的方法都是间接的动态方法:一个是动态地进行变量赋值,通过修改命名空间而植入变量;一个是动态地执行代码,可以说是通过“走后门”的方式,安插了变量。 两种方法殊途同归,不管是白猫还是黑猫,它们都抓到了老鼠。这两种方法已经给我们带来了很有价值的启发,同时,因为它们,群内小伙伴们更是发散地讨论一些相关联的话题,例如:S 同学提出了另一种修改命名空间中变量的写法、L 同学提到了 eval() 的意义、eval() 与 exec() 的区别、我查到了为什么要慎用 eval() 、C 与 H 同学提到了 eval() 的安全用法……虽然,某些话题无法在群聊中充分展开,但是,这些话题知识的延展联系,大大地丰富了本文开头的问题,这一个微小的问题,牵连出来了两个大的知识体系。最后,真得感谢群内的这些爱学习的优秀的同志们!除了文中提及的,还有一些同学也做了积极贡献,大家都很给力!相关链接: 《Python 动态赋值的陷阱》《详解Python拼接字符串的七种方式》eval()、exec()及其相关函数:https://www.tuicool.com/wx/vE…公众号【Python猫】, 专注Python技术、数据科学和深度学习,力图创造一个有趣又有用的学习分享平台。本号连载优质的系列文章,有喵星哲学猫系列、Python进阶系列、好书推荐系列、优质英文推荐与翻译等等,欢迎关注哦。PS:后台回复“爱学习”,免费获得一份学习大礼包。 ...

March 17, 2019 · 1 min · jiezi

D2 日报 2019年3月17日

???? 新闻➡️ 血淋淋的BUG:波音在软件开发上错在哪里? www.infoq.cn???? 开源项目➡️ Aaronepower/tokei 非中文 watch 17 star 1812 fork 128 一个显示代码信息的命令行工具,它可以统计指定目录下的文件数以及代码/注释/空行的数量,并按照语言分组显示 github.com➡️ skywind3000/awesome-cheatsheets watch 202 star 4070 fork 703 超级速查表 - 编程语言、框架和开发工具的速查表,单个文件包含一切你需要知道的东西 github.com➡️ Sorosliu1029/Jike-Metro watch 5 star 120 fork 16 即刻 API Python SDK github.com➡️ 0neSe7en/jikefm watch 1 star 8 fork 1 在命令行收听晚安电台 github.com➡️ traduora/traduora watch 11 star 651 fork 34 一个在 ProductHunt 斩获 103 赞的开源翻译平台,支持多人协作在线翻译,可导入导出 JSON、CSV、YAML 等多种文本格式 github.com➡️ dli/paint 非中文 watch 58 star 1953 fork 140 在线制作油画的工具 github.com➡️ Swizec/useDimensions watch 2 star 121 fork 2 测量 DOM 节点尺寸(宽高)和位置(X、Y)的 Hook github.com➡️ sindresorhus/type-fest 非中文 watch 22 star 815 fork 19 一个 TypeScript 扩充类型集合 github.com➡️ stereobooster/package.json 非中文 watch 18 star 618 fork 27 package.json 参数详解,并且提供了该参数相应的案例 github.com➡️ jkchao/typescript-book-chinese watch 50 star 1278 fork 106 深入理解 TypeScript 中文版 github.com➡️ SwiftOldDriver/iOS-Weekly watch 207 star 2258 fork 188 ???????? 老司机 iOS 周报 github.com➡️ sherlock-project/sherlock watch 68 star 3272 fork 250 可在各大社交平台检查用户名是否被占用 github.com➡️ lyricat/wechat-format watch 11 star 412 fork 36 一个用 Markdown 生成微信公众号模版的排版工具。除了标准的 HTML 格式,代码块、表格、字符标注都有很好的体验 github.com➡️ HelloGitHub/HelloGitHub01.md at master · 521xueweihan/HelloGitHub · GitHub github.com???? 分享➡️ Vue倔强青铜-入门和组件化通信G juejin.im➡️ 微软前端社招笔试详解 juejin.im➡️ 写给初级前端的面试经验 juejin.im???? 工具➡️ Juice FX by CodeManu 非中文 帮组你在游戏中为精灵元素添加摆动,跳跃和波浪扭曲效果 codemanu.itch.io➡️ Mason Front-end as a Service www.trymason.com☕️ 更优雅地阅读阅读我们精心排版之后的页面 《D2 日报 2019年3月17日》???? 往期回顾您可以访问下面的链接浏览往期内容,或者模糊检索。https://daily.fairyever.com???? 提交分享你的发现和创造 投稿/提交方式???? 如何获取日报➡️ 官方官方网站 ????RSS ????Github | Releases➡️ 微信公众号扫描下方二维码关注“今日前端”公众号,看日报不迷路!????公众号文章版本经过特殊优化,以提高微信环境内的阅读体验。➡️ 社区主页掘金 ????即刻 ????Segmentfault简书开源中国CSDN ...

March 17, 2019 · 1 min · jiezi

Java 高并发环境下的性能优化,揭秘支付宝技术内幕

前言高并发经常会发生在有大活跃用户量,用户高聚集的业务场景中,如:秒杀活动,定时领取红包等。为了让业务可以流畅的运行并且给用户一个好的交互体验,我们需要根据业务场景预估达到的并发量等因素,来设计适合自己业务场景的高并发处理方案。在电商相关产品开发的这些年,我有幸的遇到了并发下的各种坑,这一路摸爬滚打过来有着不少的血泪史,这里进行的总结,作为自己的归档记录,同时分享给大家。Java 高并发环境下的性能优化(附高并发视频资料和面试题等),揭秘支付宝技术内幕 私信。服务器架构业务从发展的初期到逐渐成熟,服务器架构也是从相对单一到集群,再到分布式服务。一个可以支持高并发的服务少不了好的服务器架构,需要有均衡负载,数据库需要主从集群,nosql缓存需要主从集群,静态文件需要上传cdn,这些都是能让业务程序流畅运行的强大后盾。服务器这块多是需要运维人员来配合搭建,具体我就不多说了,点到为止。大致需要用到的服务器架构如下:服务器均衡负载(如:nginx,阿里云SLB)资源监控分布式数据库主从分离,集群DBA 表优化,索引优化,等分布式nosql主从分离,集群主从分离,集群主从分离,集群redismongodbmemcachecdnhtmlcssjsimage并发测试高并发相关的业务,需要进行并发的测试,通过大量的数据分析评估出整个架构可以支撑的并发量。测试高并发可以使用第三方服务器或者自己测试服务器,利用测试工具进行并发请求测试,分析测试数据得到可以支撑并发数量的评估,这个可以作为一个预警参考,俗话说知己自彼百战不殆。第三方服务:阿里云性能测试并发测试工具:Apache JMeterVisual Studio性能负载测试Microsoft Web Application Stress Tool实战方案通用方案日用户流量大,但是比较分散,偶尔会有用户高聚的情况;场景: 用户签到,用户中心,用户订单,等服务器架构图:说明:场景中的这些业务基本是用户进入APP后会操作到的,除了活动日(618,双11,等),这些业务的用户量都不会高聚集,同时这些业务相关的表都是大数据表,业务多是查询操作,所以我们需要减少用户直接命中DB的查询;优先查询缓存,如果缓存不存在,再进行DB查询,将查询结果缓存起来。更新用户相关缓存需要分布式存储,比如使用用户ID进行hash分组,把用户分布到不同的缓存中,这样一个缓存集合的总量不会很大,不会影响查询效率。方案如:用户签到获取积分计算出用户分布的key,redis hash中查找用户今日签到信息如果查询到签到信息,返回签到信息如果没有查询到,DB查询今日是否签到过,如果有签到过,就把签到信息同步redis缓存。如果DB中也没有查询到今日的签到记录,就进行签到逻辑,操作DB添加今日签到记录,添加签到积分(这整个DB操作是一个事务)缓存签到信息到redis,返回签到信息注意这里会有并发情况下的逻辑问题,如:一天签到多次,发放多次积分给用户。用户订单这里我们只缓存用户第一页的订单信息,一页40条数据,用户一般也只会看第一页的订单数据用户访问订单列表,如果是第一页读缓存,如果不是读DB计算出用户分布的key,redis hash中查找用户订单信息如果查询到用户订单信息,返回订单信息如果不存在就进行DB查询第一页的订单数据,然后缓存redis,返回订单信息用户中心计算出用户分布的key,redis hash中查找用户订单信息如果查询到用户信息,返回用户信息如果不存在进行用户DB查询,然后缓存redis,返回用户信息其他业务上面例子多是针对用户存储缓存,如果是公用的缓存数据需要注意一些问题,如下注意公用的缓存数据需要考虑并发下的可能会导致大量命中DB查询,可以使用管理后台更新缓存,或者DB查询的锁住操作。以上例子是一个相对简单的高并发架构,并发量不是很高的情况可以很好的支撑,但是随着业务的壮大,用户并发量增加,我们的架构也会进行不断的优化和演变,比如对业务进行服务化,每个服务有自己的并发架构,自己的均衡服务器,分布式数据库,nosql主从集群,如:用户服务、订单服务;消息队列秒杀、秒抢等活动业务,用户在瞬间涌入产生高并发请求场景:定时领取红包,等服务器架构图:一级缓存高并发请求连接缓存服务器超出服务器能够接收的请求连接量,部分用户出现建立连接超时无法读取到数据的问题;因此需要有个方案当高并发时候时候可以减少命中缓存服务器;这时候就出现了一级缓存的方案,一级缓存就是使用站点服务器缓存去存储数据,注意只存储部分请求量大的数据,并且缓存的数据量要控制,不能过分的使用站点服务器的内存而影响了站点应用程序的正常运行,一级缓存需要设置秒单位的过期时间,具体时间根据业务场景设定,目的是当有高并发请求的时候可以让数据的获取命中到一级缓存,而不用连接缓存nosql数据服务器,减少nosql数据服务器的压力比如APP首屏商品数据接口,这些数据是公共的不会针对用户自定义,而且这些数据不会频繁的更新,像这种接口的请求量比较大就可以加入一级缓存;服务器架构图:静态化数据高并发请求数据不变化的情况下如果可以不请求自己的服务器获取数据那就可以减少服务器的资源压力。对于更新频繁度不高,并且数据允许短时间内的延迟,可以通过数据静态化成JSON,XML,HTML等数据文件上传CDN,在拉取数据的时候优先到CDN拉取,如果没有获取到数据再从缓存,数据库中获取,当管理人员操作后台编辑数据再重新生成静态文件上传同步到CDN,这样在高并发的时候可以使数据的获取命中在CDN服务器上。CDN节点同步有一定的延迟性,所以找一个靠谱的CDN服务器商也很重要

March 17, 2019 · 1 min · jiezi

Eclipse提交项目到GitHub以及解决代码冲突

前言:来这家公司上班后,开始使用Git作为项目版本控制系统,由于以前用的是SVN,所以对Git也就简单学习了一下。但是,实践出真知,当开始使用Git后,发现遇到了不少问题,也遇到过血的教训,于是决定记录一下,方便以后查看。一、Eclipse安装Git插件如果是比较新的Eclipse版本,默认就已经安装了Git插件。菜单栏 –> Help –> About Eclipse,如下图:如果有这个图标,表示Eclipse已经安装了Git插件,如果没有这个图标,就到Eclipse插件市场下载Git插件,具体步骤自行百度谷歌。二、Eclipse提交代码到GitHub1、登录GitHub,创建代码仓库登录github,然后在右上角+号下拉列表里找到New repository,创建一个新的仓库。在Repository name填入testgit,其他保持默认设置,点击Create repository按钮,就成功地创建了一个空的Git仓库。 创建完成后如下图:将最上方的仓库地址(也就是这个:https://github.com/你的GitHub账号名称/Git仓库名称.git)复制下来,后面要用到。2、在Eclipse中创建要发布到GitHub的项目我这里是创建了一个最简单的Spring Boot项目,结构如下:3、与GitHub建立连接,发布项目到GitHub3.1 share project及创建本地Git仓库选中要发布的项目 –> 右击 –> Team –> Share Project…,勾选Use or create repository in parent folder ofproject,点击红色箭头处,也就是项目,点击Create Repository按钮,会在后面显示的路径下建立本地仓库,最后点击Finish按钮即可。效果如下:文件会变成未提交状态,此时我们可以提交代码到本地仓库。3.2 提交代码到本地Git仓库为了方便提交代码到Git,我们在Eclipse中打开相应的视图窗口,菜单栏Window –> Show View –> Other…,在输入框中输入git,选择Git Staging,确定即可。选择项目,切换到Git Staging视图,在未提交文件区选择要提交的文件,拖到下面待提交文件区或者右击选择的文件选择Add to Index,填写提交信息,点击Commit将文件提交到本地Git仓库。3.3 发布项目到GitHub选中要发布的项目 –> 右击 –> Team –> Remote –> Push…,粘贴URI(也就是GitHub仓库地址,https://github.com/你的GitHub账号名称/Git仓库名称.git),填写GitHub用户名User、密码Password,点击next。点击Source ref的下拉框,选择master [branch],然后点击Add Spec,下方Specifications for push下面会出现要提交的分支信息,点击Next,再点击Finish,最后点击OK就完成了。最后在GitHub上查看项目。三、Eclipse中使用Git提交代码流程:一般是先commit到本地仓库,然后再pull更新远程仓库代码到本地,如果有冲突,文件会标红,解决冲突了再commit,最后push到远程仓库。用血的教训得到的注意点:一定要经常commit代码到本地仓库!当初就是因为没有提交代码到本地仓库,导致本地写的代码被远程仓库的代码覆盖了,周末加班重新写那些丢失的代码!四、Eclipse中解决代码冲突刚开始使用Git时,出现冲突后修改冲突部分,再提交到本地仓库,结果所有文件都冲突了,对比却又是一样的,当时不知道怎么办,就在另外的工作空间重新拉取一套代码,把修改的代码加进去。后来又遇到了,于是就找资料看怎么解决冲突,所以这里记录一下。比如我现在的项目冲突情况如下:现在我们解决冲突,比如改为下面这样:右击冲突文件 –> Team –> Add to Index此时,冲突文件变为修改图标样式,Git Staging视图中变成下图:后面就是正常的提交代码流程了,commit到本地仓库,再push到远程仓库。五、参考资料Eclipse 提交项目到 GitHubeclipse 中git解决冲突eclipse 中 git 解决冲突(重点)

March 16, 2019 · 1 min · jiezi

D2 日报 2019年3月16日

???? 新闻➡️ 百度总裁张亚勤宣布退休 mp.weixin.qq.com➡️ Android Q Beta登场,新特性抢先看! 玉刚说 mp.weixin.qq.com➡️ 特别列明AirPods:科学家联名警告慎用无线设备 据《每日邮报》消息,《每日邮报》刊登了一篇报道《苹果的无线耳机AirPods危险吗?》,文章称来自世界40个国家的250名科学家已联合签名,并向世卫组织和联合国发出请愿书,警告不要大量使用会发出无线辐射的、用于Wi-Fi、蓝牙和通讯的设备,其中特别列明苹果公司的AirPods无线耳机 www.ithome.com???? 开源项目➡️ jaywcjlove/stylus-px2rem 非中文 watch 1 star 24 fork 3 将 Stylus 中的 px 转换成 rem github.com➡️ bilibili/overlord watch 7 star 139 fork 16 Overlord是哔哩哔哩基于Go语言编写的memcache和redis&cluster的代理及集群管理功能,致力于提供自动化高可用的缓存服务解决方案 github.com➡️ pajasevi/UnCSS-Online 非中文 watch 8 star 136 fork 21 帮你删除无用 css 样式 github.com➡️ skanehira/docui watch 26 star 983 fork 41 终端 Docker 管理工具,自带一个终端界面。使用该工具可以方便的通过界面管理 docker 不用再记那些命令 github.com➡️ sym233/core-values-encoder watch 54 star 1595 fork 221 核心价值观编码 github.com➡️ dawnlabs/carbon 非中文 watch 224 star 18809 fork 902 源代码语法高亮导出图片工具 github.com➡️ selfteaching/the-craft-of-selfteaching watch 31 star 240 fork 273 李笑来的 Python 学习内容 github.com???? 分享➡️ 由图片乱码所想 前端中的二进制以及相关操作与转换 juejin.im➡️ 致 Web 诞生30周年:Web 改变了这个世界! www.chinaw3c.org➡️ 我最终是怎么玩转了 Vue 的作用域插槽 juejin.im➡️ VS Code有哪些奇淫巧技? www.zhihu.com➡️ 前端杂谈: 如何实现一个 Promise? zhuanlan.zhihu.com➡️ Web 实时推送技术的总结 juejin.im➡️ Chrome插件推荐 juejin.im???? 网站➡️ Sketch Swap 以画换画的一个小网站,通过绘画一副简笔画提交后可以得到别人的一幅绘画,可以观看对方绘画过程 www.sketchswap.com➡️ 前端导航 前端开发网址导航 webjike.com➡️ Moe Tools 一个程序员工具箱 t.boxmoe.cn➡️ Color.review 非中文 超棒的工具,帮你找到适用于各种地方的很漂亮的颜色 color.review➡️ Free templates for product management 非中文 一份产品管理免费资源列表 usefyi.com➡️ Slopes 非中文 非常酷的网站,你可以在上面创建自己独特的线条艺术作品 tinkersynth.com➡️ Culrs 非中文 一个精心制作的调色板网站 culrs.com???? 工具➡️ A semantic tool on our chat logs 非中文 一个用于聊天日志的语义工具 dailyprog.org➡️ ONES 企业级研发管理解决方案 ones.ai➡️ Generate Index 一款 VSCode 插件,为你自动生成文件索引列表,允许使用 JavaScript 自定义生成的代码 marketplace.visualstudio.com➡️ Supernova Studio 非中文 将 sketch 设计文件转为 iOS, android, react and flutter 工程 supernova.io???? 设计➡️ Charts 非中文 最全面的 sketch 图表模板,可以免费使用 www.ls.graphics➡️ Animated SVG Icons Pack 非中文 一组 svg 动画图标 outlane.co➡️ Vector Emoji 非中文 矢量 Emoji 表情素材 applypixels.com☕️ 更优雅地阅读阅读我们精心排版之后的页面 《D2 日报 2019年3月16日》???? 往期回顾您可以访问下面的链接浏览往期内容,或者模糊检索。https://daily.fairyever.com???? 提交分享你的发现和创造 投稿/提交方式???? 如何获取日报➡️ 官方官方网站 ????RSS ????Github | Releases➡️ 微信公众号扫描下方二维码关注“今日前端”公众号,看日报不迷路!????公众号文章版本经过特殊优化,以提高微信环境内的阅读体验。➡️ 社区主页掘金 ????即刻 ????Segmentfault简书开源中国CSDN ...

March 16, 2019 · 2 min · jiezi

2019年2月份Github上收获最多Star的10个Java项目

该文已加入笔主的开源项目——JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目),地址:https://github.com/Snailclimb… 。觉得不错的话,记得点个Star。1. JavaGuideGithub地址: https://github.com/Snailclimb/JavaGuideStar: 27.2k (4,437 stars this month)介绍: 【Java学习+面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识。2.DoraemonKitGithub地址: https://github.com/didi/Dorae...Star: 5.2k (3,786 stars this month)介绍: 简称 “DoKit” 。一款功能齐全的客户端( iOS 、Android )研发助手,你值得拥有。3.advanced-javaGithub地址:https://github.com/doocs/advanced-javaStar:11.2k (3,042 stars this month)介绍: 互联网 Java 工程师进阶知识完全扫盲。4. spring-boot-examplesGithub地址:https://github.com/ityouknow/…star: 9.6 k (1,764 stars this month)介绍: Spring Boot 教程、技术栈示例代码,快速简单上手教程。5. mallGithub地址: https://github.com/macrozheng/mallstar: 7.4 k (1,736 stars this month)介绍: mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。 后台管理系统包含商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等模块。6. fescarGithub地址:https://github.com/alibaba/fescarstar: 6.0 k (1,308 stars this month)介绍: 具有 高性能 和 易用性 的 微服务架构 的 分布式事务 的解决方案。(特点:高性能且易于使用,旨在实现简单并快速的事务提交与回滚。)7. h4ckerGithub地址:https://github.com/The-Art-of…star: 2.1 k (1,303 stars this month)介绍: 该仓库主要由Omar Santos维护,包括与道德黑客/渗透测试,数字取证和事件响应(DFIR),漏洞研究,漏洞利用开发,逆向工程等相关的资源。8. spring-bootGithub地址: https://github.com/spring-projects/spring-bootstar: 34.8k (1,073 stars this month)介绍: 虽然Spring的组件代码是轻量级的,但它的配置却是重量级的(需要大量XML配置),不过Spring Boot 让这一切成为了过去。 另外Spring Cloud也是基于Spring Boot构建的,我个人非常有必要学习一下。关于Spring Boot官方的介绍:Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”…Most Spring Boot applications need very little Spring configuration.(Spring Boot可以轻松创建独立的生产级基于Spring的应用程序,只要通过 “just run”(可能是run ‘Application’或java -jar 或 tomcat 或 maven插件run 或 shell脚本)便可以运行项目。大部分Spring Boot项目只需要少量的配置即可)9. arthasGithub地址:https://github.com/alibaba/arthasstar: 10.5 k (970 stars this month)介绍: Arthas 是Alibaba开源的Java诊断工具。10. tutorialsGithub地址:https://github.com/eugenp/tutorialsstar: 12.1 k (789 stars this month)介绍: 该项目是一系列小而专注的教程 - 每个教程都涵盖Java生态系统中单一且定义明确的开发领域。 当然,它们的重点是Spring Framework - Spring,Spring Boot和Spring Securiyt。 除了Spring之外,还有以下技术:核心Java,Jackson,HttpClient,Guava。专注Java知识和面试技能分享!我已经整理好了一份Java 学习必备的书籍+视频+文档汇总,内容比较多,你可以在公众号后台回复关键“1”,我会免费无套路把这些都给你。 ...

March 15, 2019 · 1 min · jiezi

原生骨架库模版功能上线,零耦合。

前言前文章地址首先,原有的骨架库实现的大概思路:如果你开启了动画,框架会根据view内的所有subViews的位置,映射出一组一模一样的CALayer动画,并进行管理。目录技术瓶颈模版功能 - 展示模版功能 - 使用方式模版功能 - 其他细节技术瓶颈如果使用约束进行布局,例如知名的第三方库Masonry布局,大部分只需要2个约束就可以很好地布局。但是, 2个约束就可以很好地布局是在数据已经填充的前提下,如果没有数据,则frame信息是完全不对。因此,映射不出合理的动画。本框架采用的是AOP编程,最初地思想是开发者尽量不需要动自己原有的代码,就可以完成动画的设置。但是,当你使用后会发现,会于原代码产生一定耦合,不会利于他人阅读和维护。我们将骨架展示给用户时,大部分情况是这样的:可能并不需要很复杂的view,子view并不需要完全展示给用户可能是很个性化的view(因为映射出的动画,并不能保证好看,又需要调试)可能是通用的view,很多地方共用一个就行了那么模版功能特别适合你。模版功能 - 展示交流群TABAniamted交流群:304543771提出你的意见模版功能 - 使用方式模版功能是库的一个新功能,并不是一个新的库。模版功能只针对常用的表格组件。开启和结束动画的方式不变唯一的改变就是在表格初始化的时候,注册模版,如下- (UICollectionView *)collectionView { if (!_collectionView) { UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, kNavigationHeight, kScreenWidth, kScreenHeight-kNavigationHeight) collectionViewLayout:layout]; _collectionView.backgroundColor = [UIColor whiteColor]; _collectionView.dataSource = self; _collectionView.delegate = self; _collectionView.animatedDelegate = self; _collectionView.showsHorizontalScrollIndicator = NO; _collectionView.showsVerticalScrollIndicator = NO; // 注册模版 [_collectionView registerTemplateClassArray:@[[TemplateCollectionViewCell class], [TemplateSecondCollectionViewCell class]]]; } return _collectionView;}模版功能 - 其他细节cell模版需要自己写,布局写死,想什么样就什么样但需要继承自TABBaseCollectionViewCell或TABBaseTableViewCell以table举例,TABBaseTableViewCell中的cellHeight方法,需要你在子类重写,并指定数值,这个返回值就是改模版在动画是展示的高度+ (NSNumber *)cellHeight { return [NSNumber numberWithFloat:10+headImgWidth+5+80+10+imgWidth];}模版功能依旧根据animationType设置动画类型使用isUseTemplate属性切换为模版模式,可以在动画开启前随意切换。模版中的组件,使用经典类型的动画,依旧需要指定动画类型提供两种方式注册模版,一个section和多section,多个section是以一个class数组形式储存。言外之意,数组中的模版类和section一一对应。- (void)registerTemplateClassArray:(NSArray <Class> *)classArray;最后如有问题,加入交流群:304543771github地址:https://github.com/tigerAndBu… ...

March 15, 2019 · 1 min · jiezi

windows下使用git拉取github上的项目

1 首先在windows下安装git(这个教程网上非常多,我就附个链接吧 )git安装2 本地打开git bash3 使用ssh-keygen命令生成自己的公钥和私钥。首先输入ssh-keygen,这里会提示你输入私钥保存的位置,直接回车使用默认位置即可,后面会两次提示输入密码 直接回车这里标红的两个文件 id_rsa和id_rsa.pub分别是私钥和公钥4 查看生成的秘钥 此时打开C:UsersAdministrator.ssh 文件夹(.ssh文件夹默认是隐藏的,要查看需要设置显示隐藏文件,或直接输入路径)。这是存放秘钥的文件夹。其中id_rsa是私钥文件,id_rsa.pub是公钥文件。5进入https://github.com,如果没有先注册账号,登录github。进入你的项目,依次点击setting->deploy keys->add deploy key6 添加公钥(公钥就是第三步中生成的id_rsa.pub文件) 填写表单 (titile可以随意填写,key就是将id_rsa.pub中的内容复制粘贴即可。) 勾选 allow write acssess, 点击add key.7本地拉取项目 git clone git@githb.com/xxxxx.git(你的git仓库地址,就是左侧code选项卡中,如下图标红的位置)注意 如果在拉取的过程中报错 Permission denied (publickey) 可以参考https://www.cnblogs.com/eooox…

March 15, 2019 · 1 min · jiezi

彻底了解web开发,熟悉建站过程

服务端开发基础前端开发 最终还是属于 Web 开发 中的一个分支,想要成为一名合格的前端开发人员,就必须要 充分理解Web 的概念。如何建立一个Blog网站 开始-明确业务-根据分析需求-设计功能-具体实现功能-部署上线-结束web学习的知识如何应用?1、网页开发技术(硬性)HTML —— 网页内容结构(GUI)CSS —— 网页外观样式(GUI)JavaScript —— 编程语言(可以用于调用浏览器提供的 API)Web APIs —— 网页交互(界面功能)jQuery —— 便捷手段(糖果而已,不是必要的)2、编程能力 / 编程思想 / 解决问题的思路(软性)我要做什么(我要得到什么),我目前有什么(我能拿到什么)至此,我们已经可以独立完成网页开发了,具体能完成的东西就是一个一个的网页,而且还能给这个页面加上一些动态的交互。但是这距离成为一个网站还有一些路要走。还需要学习什么?1、想要完成完整的 Web 网站,还需要学习什么? 搭建 WEB 服务器(提供网站服务的机器) HTTP(浏览器与服务端的通讯协议) 服务端开发(动态网页技术) 数据库操作(服务端存储数据方式) AJAX(浏览器与服务端的数据交互方式)搭建web服务器 ##、服务器(提供服务)指的就是一台安装特定的软件的公共计算机,用于专门用于提供特定的服务。按照服务类型的不同,又划分为:Web 服务器、数据库服务器、文件服务器等等。客户端(使用服务)指的是在一次服务过程中使用这个服务的设备(网络端点)。目前咱们最常见的客户端就是浏览web服务器软件3.1. Web 服务器软件Nginx ········································ 反向代理Apache ····································· PHPIIS ·············································· ASP.NETTomcat ····································· Java安装 Web 服务器软件这里不详细介绍安装配置问题,可以自行Google请求响应流程用户打开浏览器地址栏输入我们需要访问的网站网址(URL)浏览器通过 DNS 服务器获取即将访问的网站 IP 地址浏览器发起一个对这个 IP 的请求服务端接收到这个请求,进行相应的处理服务端将处理完的结果返回给客户端浏览器浏览器将服务端返回的结果呈现到界面上

March 15, 2019 · 1 min · jiezi

【基础】github 配置 SSH keys

1、ssh定义2、为什么要用ssh?3、ssh的用处4、如何生成ssh1. 检查你的电脑是否已经存在ssh,可能你已经创建mac下检查:打开终端 执行```l s -al ~/.ssh 生成$ ssh-keygen -t rsa -b 4096 -C “your_email@example.com"5、github如何配置ssh

March 14, 2019 · 1 min · jiezi

D2 日报 2019年 03月 13日

新闻➡️ 重磅!F5以6.7亿美元收购开源服务器Nginx www.infoq.cn➡️ Google 宣布开源文档写作项目 Season of Docs www.solidot.org➡️ Flutter Http 库 Dio 2.1 正式发布 juejin.im➡️ DBeaver 社区版 6.0 正式发布,可视化数据库管理工具 www.oschina.net开源项目➡️ yujiangshui/A-Programmers-Guide-to-English watch 544 star 6260 fork 552 专为程序员编写的英语学习指南 v1.2 github.com➡️ HeLiangHIT/picture_scrapy watch 1 star 2 fork 2 闲着也是闲着,爬点美女看看吧 github.com➡️ HeLiangHIT/code_banner watch 1 star 10 fork 3 高端大气上档气的banner生成工具和图案集合,python脚本 github.com➡️ xalley/wechat-db-decrypt watch 7 star 77 fork 19 解密Windows微信聊天记录数据库 github.com➡️ hstcscolor/awesome-erlang-cn watch 14 star 95 fork 40 Erlang资源大全中文版 github.com➡️ HcySunYang/vue-design watch 154 star 3461 fork 383 ????逐行级别的源码分析 github.com➡️ KidkArolis/jetpack 非中文 watch 7 star 1269 fork 17 简化 Webpack 的配置,让大多数情况下可以不写配置文件,直接使用 Webpack github.com➡️ Countly/countly-server 非中文 watch 223 star 3832 fork 744 一个开源的网站统计后端,带有 Web 界面 github.com➡️ shimohq/chinese-programmer-wrong-pronunciation watch 304 star 8382 fork 736 中国程序员容易发音错误的单词 github.com➡️ vadimdemedes/ink 非中文 watch 88 star 9909 fork 210 React 打造的的交互命令行工具 github.com➡️ vditor 一款浏览器端的 Markdown 编辑器 gitee.com➡️ whinc/web-console watch 1 star 36 fork 1 基于 H5 开发的移动端 Web 调试工具,高度还原了 Chrome DevTools 功能和交互 github.com➡️ Sam618/react-keep-alive 非中文 watch 0 star 2 fork 0 React 的 keep alive 组件 github.com➡️ pranaygp/vscode-css-peek watch 4 star 47 fork 22 VScode 插件,从 HTML 文件快速跳转到 CSS 的定义 github.com➡️ victordibia/handtrack.js 非中文 watch 10 star 417 fork 23 基于 Tensorflow.js 的手部跟踪与交互 github.com➡️ xueenze/Android-Crosswalk-Hybrid watch 1 star 2 fork 0 基于Crosswalk的Android混合H5开发框架 github.com➡️ findingsea/jikeme watch 1 star 5 fork 1 使用 Go 语言开发的一个摸鱼工具 github.com➡️ AShujiao/vscode-maxPlus watch 1 star 1 fork 0 一个开源的 VSCode 插件,让你能在 vscode 上划水看游戏资讯 github.com分享➡️ 如何自动搞定全站图片的alt属性? www.infoq.cn➡️ JavaScript到底是面向对象还是基于对象? www.infoq.cn➡️ Web scraping with Electron 非中文 采用Electron来进行网页爬取 en.jeffprod.com教程➡️ 计算机科学速成课(视频) www.yuque.com➡️ 如何使用 docker 部署前端应用 juejin.im➡️ 让你的网页更丝滑(一) juejin.im网站➡️ CDNPerf - CDN Performance and Uptime monitoring, comparison and analytics - RUM data 非中文 通过请求速度,比较各大 CDN 的性能表现 www.cdnperf.com➡️ Vector Logo Zone 非中文 该网站提供 SVG 格式的各种 Logo 文件下载,目前一共有 1,080个公司/项目的3,458个 Logo www.vectorlogo.zone更优雅地阅读阅读我们精心排版之后的页面 《D2 日报 2019年 03月 13日》往期回顾官网关于 D2 DailyD2 日报是开源组织 D2 Projects 下的一个公益新闻类开源项目。宗旨是一切资源免费且开源,但是希望每个人既是读者也是分享者,如果有足够的能力,你也可以成为开发者。请在每天闲(mo)暇(yu)时光享受日报带来的丰富知识,也请在自己发现优质资源时随手分享给大家。???????? 分享你的发现和创造 投稿/提交在哪里可以看到日报官网Github掘金即刻Segmentfault简书开源中国CSDN ...

March 13, 2019 · 2 min · jiezi

理解react高阶组件(装饰器)

首先在正式的高阶组件之前我们先来了解一下函数的类似操作:function hello () { console.log(‘hello’)}function WrapperHello (fn) { return function () { console.log(‘before’) fn && fn() console.log(‘after’) }}hello = WrapperHello(hello)hello()以上这段代码的输出会先输出before,然后 hello,最后再是after,hello函数相当于在外包裹了一层统一逻辑再进行了返回,并且声明是又将原本的hello函数进行了覆盖,这就是高阶组件的基础原理。然后我们再写一个基础的高阶组件对比一下:import React, { Component, Fragment } from ‘react’function WrapperHello (Comp) { class WrapComp extends Component { render () { return ( <Fragment > <div >这是高阶组件特有的函数</div > <Comp { …this.props }/> </Fragment > ) } } return WrapComp}@WrapperHelloclass Hello extends Component { render () { return ( <div >Hello</div > ) }}export default Hello那么在这呢,不难发现其实组件也是一个函数,我们采用了同种思想对其进行了统一的数据处理,在WrapperHello函数中传入的Comp组件,然后我们统一返回一个WrapComp函数,其中Comp在render的时候我们传入和父级传递的所有props进行数据的全部交互,然后再在Hello组件上我们用@符号进行一个简易的写法,实际上就是和之前函数包裹一样的原理进行了一次声明,那么,我们最后输出的组件Hello,他的显示就会包括了我们高阶组件中的‘ <div >这是高阶组件特有的函数</div >’元素了。高阶组件主要又分为属相代理和反向继承两种类型,举例中的函数就属于属相代理的类型。反向继承的例子:function WrapperHello (Comp) { class WrapComp extends Component { componentDidMount () { console.log(‘高阶组件新增的生命周期,加载完成’) } render () { return ( <Fragment > <Comp { …this.props }/> </Fragment > ) } } return WrapComp}我们可以通过componentDidMount来修改原有组件生命周期发生的事件,这就是反向继承的方式。记住,高阶函数返回的是一个函数,我们只是对其进行了相对应的包装。如果有好的建议和问题请指出,谢谢 ...

March 12, 2019 · 1 min · jiezi

Cocopods基础使用

一、安装和使用Cocopods网上已有很多教程,参考示例:CocoaPods安装教程二、组件库支持Cocopods方式引入1.创建远程代码仓库创建远程代码仓库(并不是podspec文件的仓库),此仓库放的是源代码。可以在GitHub上创建仓库。2.创建远程podspec仓库如果要发布到Cocopods的官方spec仓库(公开的),那么就不需要创建。当然私有库是需要创建的,在这一步两者不一样。公开库参考示例:发布开源库到Cocopods官方仓库3.创建本地代码工程可以使用pod命令创建,得到一个工程模板,并且可以根据需要配置工程,如下:命令创建工程模板pod lib create <组件库名>工程配置选择选择平台What platform do you want to use?? [ iOS / macOS ] iOS选择语言What language do you want to use?? [ Swift / ObjC ] ObjC是否自动生成一个用来做demo测试的模板库,建议Yes,后面方便测试 Would you like to include a demo application with your library? [ Yes / No ] Yes是否集成测试框架Which testing frameworks will you use? [ Specta / Kiwi / None ] NoneUI 测试Would you like to do view based testing? [ Yes / No ] No指定类前缀What is your class prefix? WT4.编写podspec文件如果用第三步的命令创建工程模板,那么在Podspec Metadata目录下已经自动生成了。如果是已有的工程或者库文件目录,也可以利用Pod命令自己制作.podspec文件,命令如下:pod spec cretae <组件库名>参考链接:podspec文件的具体说明5.验证cocoaPods索引文件命令如下:pod lib lint (从本地验证你的pod能否通过验证) pod spec lint (从本地和远程验证你的pod能否通过验证) pod lib lint –verbose (加–verbose可以显示详细的检测过程,出错时会显示详细的错误信息) pod lib lint –allow-warnings (允许警告,用来解决由于代码中存在警告导致不能通过校验的问题) pod lib lint –help (查看所有可选参数,可选参数可以加多个)6.本地测试库是否可用新建工程,切换到工程目录,执行命令pod init修改podfile文件, 并添加上本地库路径pod ‘库名’, :path => ‘/Users/xxx/Documents/库名’拉取pod代码:成功后可看到我们的库并没有在pods里面,而是在Development Pods里面,可用先检测代码有没有问题。7.提交工程代码提交工程代码到远程代码仓库,可以利用git或者svn进行代码版本管理,提交代码到GitHub等8.提交podspec文件开源库提交podspec文件到Cocopods官方仓库, 当然需要现在ocopods官方仓库中注册账号,命令如下:pod trunk me (检查是否注册trunk) pod trunk register <邮箱> <注册名字> –verbose (注册命令)注册完成之后会给你的邮箱发个邮件,进入邮箱邮件里面有个链接,需要点击确认一下.之后开始提交,切换到有.podspec文件的组件工程根目录执行命令pod trunk push <组件库名>.podspec pod trunk push <组件库名>.podspec –allow-warnings私有库提交podspec文件到远程podspec仓库,和Cocopods官方库不同的是,私有仓库需要先添加到本地仓库,再push到远程仓库,因为Cocopods默认已经添加到了本地仓库(默认为master),Mac系统可以查看文件目录(/.cocoapods/repos), 私有库命令如下:添加到本地仓库, git@git.xxxx.git为远端podspec库的地址,成功之后目录(/.cocoapods/repos)除了master之外,新增了一个文件夹(<组件库名>)pod repo add <组件库名> git@git.xxxx.git查看是否添加成功pod repo listpush到远程podspec仓库pod repo push <podspec远端仓库名> <组件库名>.podspec9. 检查仓库是否发布成功pod搜索一下:pod search <组件库名>如果报错,搜索不到,建议更新下pod:pod update之后仍然搜索不到,那么进入CocoaPods缓存目录,删除缓存索引文件search_index.json:cd ~/Library/Caches/CocoaPods ls rm -f search_index.json10. pod库文件引入如果是开源库(公有的),修改podfile文件:pod ‘组件库名’如果是私有仓库,建议在podfile文件开头添加source源:source ‘https://github.com/CocoaPods/Specs.git' #官方仓库地址source ‘http://xxx/组件库.git’ #私有podspecs仓库地址最后执行命令进行安装:pod install三、Cocopods打包静态库 ...

March 12, 2019 · 1 min · jiezi

Git随手笔记

标签(空格分隔): git初始化配置git config –list 查看配置git config –global user.name 用户名git config –global user.email 邮箱~/Desktop ~表示向前系统的路径查看git历史记录git log 显示提交的历史记录git log –oneline 显示简短的历史记录git reflog 查看所有历史版本对比文件git diff 工作区和暂存区git diff –cached暂存区和历史区 也就是仓库里面git diff master 工作区和历史区版本回滚git checkout 文件名或者点 从暂存区将工作区覆盖掉,此时文件还没添加到暂存区,类似ctrl+z的效果git reset HEAD 文件名或者点 删除本次暂存区的提交 (文件被添加到暂存区了,想撤销)git reset –hard HEAD^ 回退到上一个版本git reset –hard commitID 回退到某个版本分支git checkout -b dev 创建并切换到dev分支git checkout dev 切换到dev分支git merge dev 将dev分支的提交合并到当前分支git revertgit revert 328392删除本地分支git branch -d 分支名称删除远程分支git push origin –delete 分支名称

March 11, 2019 · 1 min · jiezi

git操作指令

git下载地址:https://git-scm.com/downloads安装完成,随便找一个文件夹,点击右键会有Git GUI Here和Git Bash Here就代表安装成功,一般只用Git Bash Here。git上传github项目,操作指令:$ git init$ git add .$ git status(查看上传项目的状态)$ git commit -m “命名这次的项目(或记录这次修改项目名称)"$ git remote add origin +github上面的该仓库的https/ssh$ git push -u origin master其实这次命令也不用记,当你在github中新建仓库后,就能看见(如下图):看着这个操作,就会很顺溜的上传到仓库了,当你上传完后,刷新一下就能看到了。github项目的预览效果:第一种方法:首先:一定要记住这个站:http://htmlpreview.github.io/ ;其次是打开项目里面的index.html或者其他html页面,添加到上面网页中的【preview】框中,点击preview就可以预览了。第二种方法:在当前项目打开的html页面的链接前面添加【http://htmlpreview.github.io/?】哈哈哈,当然咱们用git不仅仅是在github中存咱们自己的项目,大部分还是为了公司的需求,还是要懂一点git操作指令地。git操作指令:git init(运行git)git add .(添加当前项目)git status(查看上传项目的状态)git diff(查看修改的内容) git config –list(检查已有的配置信息)git fetch(将远程仓库的分支及分支最新版本代码拉取到本地)git pull origin (拉取代码到本地,解决拉取代码发生的冲突)git push(推送提交本地仓库代码文件到远程仓库)git clone [url链接] (克隆下载远程仓库项目工程到本地工作区)git切换账号:git config user.name(查看用户名) git config user.email(查看邮箱地址) git config –global user.name “×××"(修改用户名)git config –global user.email “×××”(次改邮箱地址) ssh-keygen -t rsa -C “email@email.com”(本地创建ssh key) ssh -T git@github.com(验证是否成功)git cat ~/.ssh/id_rsa.pub(查看公钥地址)以上都是我自己的记录,也就是为了自己省事,以后方便自己查看指令(没有办法,自己不爱去死记这些东西)(′◉❥◉`)

March 11, 2019 · 1 min · jiezi

Nvidia GPU如何在Kubernetes 里工作

Nvidia GPU如何在Kubernetes 里工作本文介绍Nvidia GPU设备如何在Kubernetes中管理调度。 整个工作流程分为以下两个方面:如何在容器中使用GPUKubernetes 如何调度GPU如何在容器中使用GPU想要在容器中的应用可以操作GPU, 需要实两个目标容器中可以查看GPU设备容器中运行的应用,可以通过Nvidia驱动操作GPU显卡详细介绍可见: https://devblogs.nvidia.com/gpu-containers-runtime/Nvidia-dockerGitHub: https://github.com/NVIDIA/nvidia-dockerNvidia提供Nvidia-docker项目,它是通过修改Docker的Runtime为nvidia runtime工作,当我们执行 nvidia-docker create 或者 nvidia-docker run 时,它会默认加上 –runtime=nvidia 参数。将runtime指定为nvidia。当然,为了方便使用,可以直接修改Docker daemon 的启动参数,修改默认的 Runtime为 nvidia-container-runtime cat /etc/docker/daemon.json{ “default-runtime”: “nvidia”, “runtimes”: { “nvidia”: { “path”: “/usr/bin/nvidia-container-runtime”, “runtimeArgs”: [] } }}gpu-containers-runtimeGitHub: https://github.com/NVIDIA/nvidia-container-runtimegpu-containers-runtime 是一个NVIDIA维护的容器 Runtime,它在runc的基础上,维护了一份 Patch, 我们可以看到这个patch的内容非常简单, 唯一做的一件事情就是在容器启动前,注入一个 prestart 的hook 到容器的Spec中(hook的定义可以查看 OCI规范 )。这个hook 的执行时机是在容器启动后(Namespace已创建完成),容器自定义命令(Entrypoint)启动前。nvidia-containers-runtime 定义的 prestart 的命令很简单,只有一句 nvidia-container-runtime-hook prestart gpu-containers-runtime-hookGitHub: https://github.com/NVIDIA/nvidia-container-runtime/tree/master/hook/nvidia-container-runtime-hook gpu-containers-runtime-hook 是一个简单的二进制包,定义在Nvidia container runtime的hook中执行。 目的是将当前容器中的信息收集并处理,转换为参数调用 nvidia-container-cli 。主要处理以下参数:根据环境变量 NVIDIA_VISIBLE_DEVICES 判断是否会分配GPU设备,以及挂载的设备ID。如果是未指定或者是 void ,则认为是非GPU容器,不做任何处理。 否则调用 nvidia-container-cli , GPU设备作为 –devices 参数传入环境环境变量 NVIDIA_DRIVER_CAPABILITIES 判断容器需要被映射的 Nvidia 驱动库。环境变量 NVIDIA_REQUIRE_ 判断GPU的约束条件。 例如 cuda>=9.0 等。 作为 –require= 参数传入传入容器进程的Pidgpu-containers-runtime-hook 做的事情,就是将必要的信息整理为参数,传给 nvidia-container-cli configure 并执行。nvidia-container-clinvidia-container-cli 是一个命令行工具,用于配置Linux容器对GPU 硬件的使用。支持list: 打印 nvidia 驱动库及路径info: 打印所有Nvidia GPU设备configure: 进入给定进程的命名空间,执行必要操作保证容器内可以使用被指定的GPU以及对应能力(指定 Nvidia 驱动库)。 configure是我们使用到的主要命令,它将Nvidia 驱动库的so文件 和 GPU设备信息, 通过文件挂载的方式映射到容器中。代码如下: https://github.com/NVIDIA/libnvidia-container/blob/master/src/cli/configure.c#L272 / Mount the driver and visible devices. */ if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_MOUNT], ecaps_size(NVC_MOUNT)) < 0) { warnx(“permission error: %s”, err.msg); goto fail; } if (nvc_driver_mount(nvc, cnt, drv) < 0) { warnx(“mount error: %s”, nvc_error(nvc)); goto fail; } for (size_t i = 0; i < dev->ngpus; ++i) { if (gpus[i] != NULL && nvc_device_mount(nvc, cnt, gpus[i]) < 0) { warnx(“mount error: %s”, nvc_error(nvc)); goto fail; } }如果对其他模块感兴趣,可以在 https://github.com/NVIDIA/libnvidia-container 阅读代码。以上就是一个nvidia-docker的容器启动的所有步骤。当我们安装了nvidia-docker, 我们可以通过以下方式启动容器docker run –rm -it -e NVIDIA_VISIBLE_DEVICES=all ubuntu:18.04在容器中执行 mount 命令,可以看到名为 libnvidia-xxx.so 和 /proc/driver/nvidia/gpus/xxx 映射到容器中。 以及 nvidia-smi 和 nvidia-debugdump 等nvidia工具。# mount ## …./dev/vda1 on /usr/bin/nvidia-smi type ext4 (ro,nosuid,nodev,relatime,data=ordered)/dev/vda1 on /usr/bin/nvidia-debugdump type ext4 (ro,nosuid,nodev,relatime,data=ordered)/dev/vda1 on /usr/bin/nvidia-persistenced type ext4 (ro,nosuid,nodev,relatime,data=ordered)/dev/vda1 on /usr/bin/nvidia-cuda-mps-control type ext4 (ro,nosuid,nodev,relatime,data=ordered)/dev/vda1 on /usr/bin/nvidia-cuda-mps-server type ext4 (ro,nosuid,nodev,relatime,data=ordered)/dev/vda1 on /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered)/dev/vda1 on /usr/lib/x86_64-linux-gnu/libnvidia-cfg.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered)/dev/vda1 on /usr/lib/x86_64-linux-gnu/libcuda.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered)/dev/vda1 on /usr/lib/x86_64-linux-gnu/libnvidia-opencl.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered)/dev/vda1 on /usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered)/dev/vda1 on /usr/lib/x86_64-linux-gnu/libnvidia-fatbinaryloader.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered)/dev/vda1 on /usr/lib/x86_64-linux-gnu/libnvidia-compiler.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered)devtmpfs on /dev/nvidiactl type devtmpfs (ro,nosuid,noexec,relatime,size=247574324k,nr_inodes=61893581,mode=755)devtmpfs on /dev/nvidia-uvm type devtmpfs (ro,nosuid,noexec,relatime,size=247574324k,nr_inodes=61893581,mode=755)devtmpfs on /dev/nvidia-uvm-tools type devtmpfs (ro,nosuid,noexec,relatime,size=247574324k,nr_inodes=61893581,mode=755)devtmpfs on /dev/nvidia4 type devtmpfs (ro,nosuid,noexec,relatime,size=247574324k,nr_inodes=61893581,mode=755)proc on /proc/driver/nvidia/gpus/0000:00:0e.0 type proc (ro,nosuid,nodev,noexec,relatime)我们可以执行nvidia-smi查看容器中被映射的GPU卡Kubernetes 如何调度GPU之前我们介绍了如何在容器中使用Nvidia GPU卡。 那么当一个集群中有成百上千个节点以及GPU卡,我们的问题变成了如何管理和调度这些GPU。Device pluginKubernetes 提供了Device Plugin 的机制,用于异构设备的管理场景。原理是会为每个特殊节点上启动一个针对某个设备的DevicePlugin pod, 这个pod需要启动grpc服务, 给kubelet提供一系列接口。type DevicePluginClient interface { // GetDevicePluginOptions returns options to be communicated with Device // Manager GetDevicePluginOptions(ctx context.Context, in *Empty, opts …grpc.CallOption) (*DevicePluginOptions, error) // ListAndWatch returns a stream of List of Devices // Whenever a Device state change or a Device disapears, ListAndWatch // returns the new list ListAndWatch(ctx context.Context, in *Empty, opts …grpc.CallOption) (DevicePlugin_ListAndWatchClient, error) // Allocate is called during container creation so that the Device // Plugin can run device specific operations and instruct Kubelet // of the steps to make the Device available in the container Allocate(ctx context.Context, in *AllocateRequest, opts …grpc.CallOption) (*AllocateResponse, error) // PreStartContainer is called, if indicated by Device Plugin during registeration phase, // before each container start. Device plugin can run device specific operations // such as reseting the device before making devices available to the container PreStartContainer(ctx context.Context, in *PreStartContainerRequest, opts …grpc.CallOption) (*PreStartContainerResponse, error)}DevicePlugin 注册一个 socket 文件到 /var/lib/kubelet/device-plugins/ 目录下,kubelet 通过这个目录下的socket文件向对应的 Device plugin 发送grpc请求。本文不过多介绍Device Plugin 的设计, 感兴趣可以阅读这篇文章: https://yq.aliyun.com/articles/498185Nvidia pluginGithub: https://github.com/NVIDIA/k8s-device-plugin为了能够在Kubernetes中管理和调度GPU, Nvidia提供了Nvidia GPU的Device Plugin。 主要功能如下支持ListAndWatch 接口,上报节点上的GPU数量支持Allocate接口, 支持分配GPU的行为。 Allocate 接口只做了一件事情,就是给容器加上 NVIDIA_VISIBLE_DEVICES 环境变量。 https://github.com/NVIDIA/k8s-device-plugin/blob/v1.11/server.go#L153// Allocate which return list of devices.func (m *NvidiaDevicePlugin) Allocate(ctx context.Context, reqs *pluginapi.AllocateRequest) (*pluginapi.AllocateResponse, error) { devs := m.devs responses := pluginapi.AllocateResponse{} for _, req := range reqs.ContainerRequests { response := pluginapi.ContainerAllocateResponse{ Envs: map[string]string{ “NVIDIA_VISIBLE_DEVICES”: strings.Join(req.DevicesIDs, “,”), }, } for _, id := range req.DevicesIDs { if !deviceExists(devs, id) { return nil, fmt.Errorf(“invalid allocation request: unknown device: %s”, id) } } responses.ContainerResponses = append(responses.ContainerResponses, &response) } return &responses, nil}前面我们提到, Nvidia的 gpu-container-runtime 根据容器的 NVIDIA_VISIBLE_DEVICES 环境变量,会决定这个容器是否为GPU容器,并且可以使用哪些GPU设备。 而Nvidia GPU device plugin做的事情,就是根据kubelet 请求中的GPU DeviceId, 转换为 NVIDIA_VISIBLE_DEVICES 环境变量返回给kubelet, kubelet收到返回内容后,会自动将返回的环境变量注入到容器中。当容器中包含环境变量,启动时 gpu-container-runtime 会根据 NVIDIA_VISIBLE_DEVICES 里声明的设备信息,将设备映射到容器中,并将对应的Nvidia Driver Lib 也映射到容器中。总体流程整个Kubernetes调度GPU的过程如下:GPU Device plugin 部署到GPU节点上,通过 ListAndWatch 接口,上报注册节点的GPU信息和对应的DeviceID。 当有声明 nvidia.com/gpu 的GPU Pod创建出现,调度器会综合考虑GPU设备的空闲情况,将Pod调度到有充足GPU设备的节点上。节点上的kubelet 启动Pod时,根据request中的声明调用各个Device plugin 的 allocate接口, 由于容器声明了GPU。 kubelet 根据之前 ListAndWatch 接口收到的Device信息,选取合适的设备,DeviceID 作为参数,调用GPU DevicePlugin的 Allocate 接口GPU DevicePlugin ,接收到调用,将DeviceID 转换为 NVIDIA_VISIBLE_DEVICES 环境变量,返回kubeletkubelet将环境变量注入到Pod, 启动容器容器启动时, gpu-container-runtime 调用 gpu-containers-runtime-hook gpu-containers-runtime-hook 根据容器的 NVIDIA_VISIBLE_DEVICES 环境变量,转换为 –devices 参数,调用 nvidia-container-cli prestart nvidia-container-cli 根据 –devices ,将GPU设备映射到容器中。 并且将宿主机的Nvidia Driver Lib 的so文件也映射到容器中。 此时容器可以通过这些so文件,调用宿主机的Nvidia Driver。本文作者:萧元阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

March 11, 2019 · 3 min · jiezi

D2 日报 2019年 03月 11日

新闻➡️ Visual Studio Code 1.32 发布 www.oschina.net➡️ 13岁女学生被捕:因发布 JavaScript 无限循环代码 - 开源中国 www.oschina.net开源项目➡️ kulics/xs watch 5 star 59 fork 3 国人开发的编程语言 github.com➡️ asdjgfr/operationRecord watch 2 star 123 fork 12 浏览器操作录屏工具,提供 Web 管理后台。记录产品,测试的沙雕操作,方便 debugger github.com➡️ myliang/x-spreadsheet 非中文 watch 96 star 4394 fork 243 基于 Canvas 的 JS 电子表格 github.com➡️ dmaydan/Maze_Solver_Generator 非中文 watch 2 star 152 fork 9 在 <canvas> 元素上绘制和解决迷宫 github.com➡️ revery-ui/revery watch 86 star 3830 fork 94 一个构建跨平台桌面应用的框架,使用 Reason 语言编写,使用 React + Redux github.com➡️ recoluan/vuepress-theme-reco 非中文 watch 2 star 30 fork 5 VuePress 博客主题 reco github.com➡️ gragland/usehooks 非中文 watch 18 star 433 fork 17 帮助你理解 React Hooks github.com➡️ esdoc/esdoc 非中文 watch 39 star 2347 fork 177 ESDoc 是一款 JS 文档生成器 github.com➡️ CharlesStover/reactn 非中文 watch 28 star 700 fork 23 React 的 “全局状态” 管理插件 github.com➡️ gotify/server 非中文 watch 41 star 1750 fork 60 一个用 Go 实现的 Restful 实时推送服务,项目还提供了一个简单的 UI。支持安卓客户端和插件扩展 github.com➡️ olive-editor/olive 非中文 watch 52 star 665 fork 67 开源视频编辑器 github.com➡️ asyncspider/spiderexam watch 0 star 33 fork 3 爬虫工程师面试试题 github.com➡️ facebook/liblogfaf 非中文 watch 37 star 355 fork 59 使用非阻塞UDP数据报记录消息的库,Facebook出品 github.com➡️ iliakan/javascript-tutorial-en Modern JavaScript Tutorial github.com➡️ stefanJi/Flutter4GitLab 非中文 watch 8 star 137 fork 7 Gitlab Flutter编写客户端 github.com➡️ luanfujun/deep-painterly-harmonization 非中文 watch 171 star 5301 fork 497 一个基于深度学习的开源项目,让图片可以毫无违和感的融入到绘画作品中 github.com➡️ jdf2e/nutui watch 31 star 282 fork 36 京东风格的轻量级移动端 Vue 组件库 github.com分享➡️ C++ Tips findingsea’s Studio findingsea.github.io➡️ Element-UI 框架 el-scrollbar 组件 juejin.im➡️ 前端九部 - 入门者手册 九部成员合著的web前端开发零基础入门手册 www.yuque.com网站➡️ Who runs China? 第十三届全国人民代表大会的代表数据可视化 news.cgtn.com➡️ 双拼入门 在线练习双拼输入法的网站 linci.co➡️ coderplanets 一个小众语言社区,可以建立各种主题的子社区 coderplanets.com工具➡️ react-meme-generator 图片上加文字的在线工具,支持摄像头,可以制作表情包 www.lijinke.cn➡️ ReactOS 非中文 ReactOS 是一个基于 Windows NT 架构设计原则的开源操作系统 www.reactos.org设计➡️ 配色参考 优设出的一组配色参考 weibo.com招聘➡️ answershuto/recruit watch 1 star 31 fork 0 阿里通信(京杭两地)求前端工程师 github.com更优雅地阅读阅读我们精心排版之后的页面 《D2 日报 2019年 03月 11日》往期回顾官网关于 D2 DailyD2 日报是开源组织 D2 Projects 下的一个公益新闻类开源项目。宗旨是一切资源免费且开源,但是希望每个人既是读者也是分享者,如果有足够的能力,你也可以成为开发者。请在每天闲(mo)暇(yu)时光享受日报带来的丰富知识,也请在自己发现优质资源时随手分享给大家。???????? 分享你的发现和创造 投稿/提交在哪里可以看到日报官网Github掘金即刻Segmentfault简书开源中国CSDN ...

March 11, 2019 · 2 min · jiezi

CSS文字交错滑动效果-001

项目展示技术难点:引用MDN解释:content: attr(data-text);是CSS中引用的HTML元素的属性名称。实例:HTMLp data-foo=“hello”>world</p>CSS[data-foo]::before { content: attr(data-foo) " “;}输出 //hello world初始样式:基本每个人都会(忽略)第一步:通过CSS3 的transform属性移动文字,样式如下 .box span:nth-child(odd) { transform: translateY(-100%); } .box span:nth-child(even) { transform: translateY(100%); }第二步:通过content 的arr属性引用的HTML元素的属性名称 <span data-text=“N”>N</span> //html .box span::before { content: attr(data-text); position: absolute; // 脱离文档流 color: red; } .box span:nth-child(odd)::before { transform: translateY(100%); } .box span:nth-child(even)::before { transform: translateY(-100%); }第三步:鼠标经过,修改transform属性就行 .box:hover span { transform: translateY(0); }项目源码了解更多,个人博客

March 10, 2019 · 1 min · jiezi

Git常用命令学习笔记

在学习了廖雪峰老师的git教程后把常用的命令总结了出来注:在使用这些命令前请安装好Git软件,地址:https://git-scm.com/downloads1、在建好的目录下来初始化一个git项目git init2、添加文件2.1、添加所有文件git add .2.2、添加指定文件git add 文件名eg: git add readme.md3、提交到仓库git commit -m “说明"eg: git commit -m “Update"4、查看仓库状态4.1、如果你修改了某个文件,我们可以通过以下命令来查看状态git status4.2、如果想知道某个文件具体修改了哪些内容,用以下命令git diff 文件名eg: git diff readme.md注:在确认修改无误后需要再次对修改的文件做git add 和 git commit命令来提交到仓库。5、显示从最近到最远的提交日志git log6、版本回退在Git中,用HEAD表示当前版本,也就是最新的提交,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。git reset –hard HEAD^7、不想回退版本找到回退之前的版本的commit版本值(sha1值),来进行反悔操作。git reset –hard commit值eg: git reset –hard f8dad 注: 这个值只需要取前五位即可。8、查看回退记录前面的反悔操作是建立在你还没关闭git bash窗口看得到回退前那个最新版本的commit id值,如果我们关闭了窗口后想反悔怎么办,使用以下命令来查看git relog

March 10, 2019 · 1 min · jiezi

Pandas之旅(二): 有关数据清理的点点滴滴

数据清洗大家好,这一期我将为大家带来我的pandas学习心得第二期:数据清理。这一步非常重要,一般在获取数据源之后,我们紧接着就要开始这一步,以便为了之后的各种操作,简单来说,我们的目标就是让数据看起来赏心悦目,规规矩矩的,所以我们会对原始的dataframe做一些必要的美容,包括规范命名,去除异常值,重新选择合适的index啊,处理缺失值,统一列的命名等等。这一期我会和大家分享一些比较好用常见的清洗方法。首先还是让我们来简单看一下本文将会用到的数据源:property_data.csv 这是一个超小型的房地产行业的数据集,大家会在文章最后找到下载地址。这篇文章我会从以下几个方面来和大家分享我的心得体会:有关缺失值的处理有关列的处理设置Index源码及数据下载地址1.有关缺失值的处理这里我们会用到 property_data.csv这个数据集,在开始处理缺失值之前,我们可以先话一分钟仔细想想,为什么实际生活中的数据从来是不完整的,原因基本有几个方面:用户忘记填写字段从旧数据库手动传输时数据丢失代码中有bug用户不填写非必须字段(比如注册的时候)因为这些原因,我每次在处理missing value的时候都会问自己两个基础问题:数据集每一列有什么特点?我们想要在处理后得到什么类型的数据(int,float,string,boolean)?带着这些疑问,我们可以开始了,首先让我们简单读取一下数据,利用head函数看看前5行,如果你还对pandas的基础知识有疑问,可以看看我上一篇文章:Pandas之旅(一): 让我们把基础知识一次撸完,申精干货import pandas as pdimport numpy as npimport osos.chdir(“F:\Python教程\segmentfault\pandas_share\Pandas之旅_02 数据清洗”)# Read csv file into a pandas dataframedf = pd.read_csv(“property_data.csv”)# Take a look at the first few rowsdf.head() PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT 0 100001000.0 104.0 PUTNAM Y 3 1 1000 1 100002000.0 197.0 LEXINGTON N 3 1.5 – 2 100003000.0 NaN LEXINGTON N NaN 1 850 3 100004000.0 201.0 BERKELEY 12 1 NaN 700 4 NaN 203.0 BERKELEY Y 3 2 1600 现在让我们看看数据的一些关键列是什么:ST_NUM:街道号码ST_NAME: 街道名称OWN_OCCUPIED: 是否用于自住NUM_BEDROOMS:卧室数量SQ_FT:面积这里可以给大家普及点房地产知识,有的时候房屋用途被明确规定,比如有的房产写的是"owner occupied only “)意思是说如果你买了,那这个房子会成为你的主要住所,不能用于出租之类的,简单理解就是自住所以现在我可以自问自答第一个问题:数据集每一列有什么特点?ST_NUM:float或int …ST_NAME:stringOWN_OCCUPIED:string … Y(“是”)或N(“否”)NUM_BEDROOMS:float或int,数字类型SQ_FT:float或int,数字类型1.1 规范的缺失值标记现在让我们关注ST_NUM这一列:# Looking at the ST_NUM columndf[‘ST_NUM’]0 104.01 197.02 NaN3 201.04 203.05 207.06 NaN7 213.08 215.0Name: ST_NUM, dtype: float64如果想查看该列的缺失值情况,我们可以利用isnull()方法,如果出现缺失值,会返回True,反之返回falsedf[‘ST_NUM’].isnull()0 False1 False2 True3 False4 False5 False6 True7 False8 FalseName: ST_NUM, dtype: bool但是其实如果我们打开csv文件,你会发现第3行是空白,还有一行在该列显示的是NA,所以结论已经有了:在pandas里表示缺省值的符号及时NA,换句话说,如果我们要表示缺省值,标准写法是NA1.2 不规范的缺失值标记同样的,这回让我们关注一下NUM_BEDROOMS这一列,我们发现出现了4种类型的表达缺省值的标记:n/aNA—na通过刚才的实践,我们已经确定NA是pandas可以识别的,那么其他的符号呢,现在让我们来测试一下df[‘NUM_BEDROOMS’]0 31 32 NaN3 14 35 NaN6 27 18 naName: NUM_BEDROOMS, dtype: objectdf[‘NUM_BEDROOMS’].isnull()0 False1 False2 True3 False4 False5 True6 False7 False8 FalseName: NUM_BEDROOMS, dtype: bool可以看到pandas识别了n/a 和NA两种符号,但是接下来我们要考虑一个问题,假设你是房地产公司的地区总经理,你每周会收到不同地区的负责人提交的表格,这些人中有的喜欢用–表示空白值,有的人喜欢用na,那应该怎么办?最简单的方式就是将所有表示空白值的符号统一放在list中,让后让pandas一次性识别:# Making a list of missing value typesmissing_values = [“na”, “–"]df = pd.read_csv(“property_data.csv”, na_values = missing_values)现在我们来看看到底发生了什么?df PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT 0 100001000.0 104.0 PUTNAM Y 3.0 1 1000.0 1 100002000.0 197.0 LEXINGTON N 3.0 1.5 NaN 2 100003000.0 NaN LEXINGTON N NaN 1 850.0 3 100004000.0 201.0 BERKELEY 12 1.0 NaN 700.0 4 NaN 203.0 BERKELEY Y 3.0 2 1600.0 5 100006000.0 207.0 BERKELEY Y NaN 1 800.0 6 100007000.0 NaN WASHINGTON NaN 2.0 HURLEY 950.0 7 100008000.0 213.0 TREMONT Y 1.0 1 NaN 8 100009000.0 215.0 TREMONT Y NaN 2 1800.0 我们可以发现只要missing_value中记录的表达空白值的符号,全部变成了规整的NaN1.3 类型不一致的异常值刚刚我们已经简单了解了在pandas中如何处理缺失值的,还有一种情况,让我们来看OWN_OCCUPIED这一列,这一列的答案只能是Y,N 但是我们发现数据集意外地出现了12,属于类型不对称df[‘OWN_OCCUPIED’].isnull()0 False1 False2 False3 False4 False5 False6 True7 False8 FalseName: OWN_OCCUPIED, dtype: bool现在我们发现12是异常值,因为它是类型错误,所以我们可以简单通过下面这个方法来检测,# Detecting numbers cnt=0for row in df[‘OWN_OCCUPIED’]: try: int(row) df.loc[cnt, ‘OWN_OCCUPIED’]=np.nan except ValueError: pass cnt+=1我们这里的策略是:循环遍历OWN_OCCUPIED列尝试将条目转换为整数如果条目可以更改为整数,请输入缺失值如果数字不能是整数,我们知道它是一个字符串,所以继续这样我们会把OWN_OCCUPIED这一列中所有类型不对的值转化为NaN,现在来看结果:df[‘OWN_OCCUPIED’]0 Y1 N2 N3 NaN4 Y5 Y6 NaN7 Y8 YName: OWN_OCCUPIED, dtype: object1.4 汇总缺失值pandas提供了更为简洁的方式,可以让我们整体了解所有column的空值:df.isnull().sum()PID 1ST_NUM 2ST_NAME 0OWN_OCCUPIED 2NUM_BEDROOMS 3NUM_BATH 1SQ_FT 2dtype: int64或者如果我们只想知道数据是否存在空值,那么可以使用以下的命令:# Any missing values?df.isnull().values.any()True1.5 替换缺失值如果我们想要替换掉缺失值,可以用fillna方法# Replace missing values with a numberdf[‘ST_NUM’].fillna(125, inplace=True)或者我们可以通过准确定位来替换缺失值:# Location based replacementdf.loc[2,‘ST_NUM’] = 125替换缺失值的一种非常常见的方法是使用中位数:# Replace using median median = df[‘NUM_BEDROOMS’].median()df[‘NUM_BEDROOMS’].fillna(median, inplace=True)df PID ST_NUM ST_NAME OWN_OCCUPIED NUM_BEDROOMS NUM_BATH SQ_FT 0 100001000.0 104.0 PUTNAM Y 3.0 1 1000.0 1 100002000.0 197.0 LEXINGTON N 3.0 1.5 NaN 2 100003000.0 125.0 LEXINGTON N 2.5 1 850.0 3 100004000.0 201.0 BERKELEY NaN 1.0 NaN 700.0 4 NaN 203.0 BERKELEY Y 3.0 2 1600.0 5 100006000.0 207.0 BERKELEY Y 2.5 1 800.0 6 100007000.0 125.0 WASHINGTON NaN 2.0 HURLEY 950.0 7 100008000.0 213.0 TREMONT Y 1.0 1 NaN 8 100009000.0 215.0 TREMONT Y 2.5 2 1800.0 2. 有关列的处理2.1 统一修改列名现在假设因为一些需求,需要我们统一修改列名,把列名改为小写,我们可以结合列表推导式轻易实现df.rename(str.lower, axis=‘columns’,inplace =True)df.columnsIndex([‘pid’, ‘st_num’, ‘st_name’, ‘own_occupied’, ’num_bedrooms’, ’num_bath’, ‘sq_ft’], dtype=‘object’)或者需要把列名中的_改为-:new_cols = [c.replace(”_”,"-") for c in df.columns]change_dict =dict(zip(df.columns,new_cols))df.rename(columns=change_dict,inplace=True)df pid st-num st-name own-occupied num-bedrooms num-bath sq-ft 0 100001000.0 104.0 PUTNAM Y 3.0 1 1000.0 1 100002000.0 197.0 LEXINGTON N 3.0 1.5 NaN 2 100003000.0 125.0 LEXINGTON N 2.5 1 850.0 3 100004000.0 201.0 BERKELEY NaN 1.0 NaN 700.0 4 NaN 203.0 BERKELEY Y 3.0 2 1600.0 5 100006000.0 207.0 BERKELEY Y 2.5 1 800.0 6 100007000.0 125.0 WASHINGTON NaN 2.0 HURLEY 950.0 7 100008000.0 213.0 TREMONT Y 1.0 1 NaN 8 100009000.0 215.0 TREMONT Y 2.5 2 1800.0 这里我没有写的精简一些,反而是复杂了,主要是想让大家回忆起之前我分享的dict使用技巧中的内容,注意这里inplace=True,导致的结果是我们的的确确修改了df所有的列名2.1 根据需求新增列假如目前我们需要新增一列,根据房屋面积大小来赋值,我们先随意把缺失值补上:df[‘sq-ft’].fillna(‘0.0’)0 10001 0.02 8503 7004 16005 8006 9507 0.08 1800Name: sq-ft, dtype: object然后新建一列rank来根据房屋面积大小赋值S=small,M=medium,B=big:df[“rank”]= pd.cut(df[‘sq-ft’], [0, 800, 1600, np.inf], labels=(“S”,“M”,“B”))df pid st-num st-name own-occupied num-bedrooms num-bath sq-ft rank 0 100001000.0 104.0 PUTNAM Y 3.0 1 1000.0 M 1 100002000.0 197.0 LEXINGTON N 3.0 1.5 NaN NaN 2 100003000.0 125.0 LEXINGTON N 2.5 1 850.0 M 3 100004000.0 201.0 BERKELEY NaN 1.0 NaN 700.0 S 4 NaN 203.0 BERKELEY Y 3.0 2 1600.0 M 5 100006000.0 207.0 BERKELEY Y 2.5 1 800.0 S 6 100007000.0 125.0 WASHINGTON NaN 2.0 HURLEY 950.0 M 7 100008000.0 213.0 TREMONT Y 1.0 1 NaN NaN 8 100009000.0 215.0 TREMONT Y 2.5 2 1800.0 B 具体实现方法我们之后会说,这里主要是用到了pandas的cut方法,非常便捷3. 设置Index在许多情况下,使用数据的唯一值标识字段作为其索引是有帮助的。这里可能我们的数据不太合适,因此我们先伪造一列Fake_Index来模拟真实场景中的真正索引df[“Fake_Index”]=[“A00”+str(i) for i in range(len(df))]df pid st-num st-name own-occupied num-bedrooms num-bath sq-ft rank Fake_Index 0 100001000.0 104.0 PUTNAM Y 3.0 1 1000.0 M A000 1 100002000.0 197.0 LEXINGTON N 3.0 1.5 NaN NaN A001 2 100003000.0 125.0 LEXINGTON N 2.5 1 850.0 M A002 3 100004000.0 201.0 BERKELEY NaN 1.0 NaN 700.0 S A003 4 NaN 203.0 BERKELEY Y 3.0 2 1600.0 M A004 5 100006000.0 207.0 BERKELEY Y 2.5 1 800.0 S A005 6 100007000.0 125.0 WASHINGTON NaN 2.0 HURLEY 950.0 M A006 7 100008000.0 213.0 TREMONT Y 1.0 1 NaN NaN A007 8 100009000.0 215.0 TREMONT Y 2.5 2 1800.0 B A008 现在我们添加的最后一列非常像真正的房屋Id了,让我们来看看这个伪造的索引是不是唯一值,可以利用is_unique来检验:df.Fake_Index.is_uniqueTrue没有问题,现在我们可以放心地把这列设置为我们真正的索引:df = df.set_index(‘Fake_Index’)df pid st-num st-name own-occupied num-bedrooms num-bath sq-ft rank Fake_Index A000 100001000.0 104.0 PUTNAM Y 3.0 1 1000.0 M A001 100002000.0 197.0 LEXINGTON N 3.0 1.5 NaN NaN A002 100003000.0 125.0 LEXINGTON N 2.5 1 850.0 M A003 100004000.0 201.0 BERKELEY NaN 1.0 NaN 700.0 S A004 NaN 203.0 BERKELEY Y 3.0 2 1600.0 M A005 100006000.0 207.0 BERKELEY Y 2.5 1 800.0 S A006 100007000.0 125.0 WASHINGTON NaN 2.0 HURLEY 950.0 M A007 100008000.0 213.0 TREMONT Y 1.0 1 NaN NaN A008 100009000.0 215.0 TREMONT Y 2.5 2 1800.0 B 现在对数据的操作容易多了,我们很多事情可以通过索引完成:# 根据索引名称切片df[‘A000’:‘A003’] pid st-num st-name own-occupied num-bedrooms num-bath sq-ft rank Fake_Index A000 100001000.0 104.0 PUTNAM Y 3.0 1 1000.0 M A001 100002000.0 197.0 LEXINGTON N 3.0 1.5 NaN NaN A002 100003000.0 125.0 LEXINGTON N 2.5 1 850.0 M A003 100004000.0 201.0 BERKELEY NaN 1.0 NaN 700.0 S # 根据索引位置切片df.iloc[1:3, 0:3] pid st-num st-name Fake_Index A001 100002000.0 197.0 LEXINGTON A002 100003000.0 125.0 LEXINGTON # 定位到具体元素df.iloc[1,2]‘LEXINGTON’总结我把这一期的ipynb文件和py文件放到了GIthub上,大家如果想要下载可以点击下面的链接:Github仓库地址: https://github.com/yaozeliang/pandas_share这一期先讲到这里,希望大家能够继续支持我,完结,撒花 ...

March 9, 2019 · 5 min · jiezi

github-page部署vue/react静态页面在线预览demo

git checkout -b “gh-pages"yarn add gh-pages修改package.json 增加 “deploy” : “gh-pages -d build” bulid是打包后生成的路径修改package.json 增加 “homepage”: “https://xxxx.github.io/项目名称"yarn run buildyarn run deploygithub setting 选择 gh-pages 分支vue-cli需要在config/index.js 将assetsublicPath: ‘/’ 改为 ‘./’

March 8, 2019 · 1 min · jiezi

Pull Request 小帖士

Forked Repo一般地,本地 forked repo 有两个远端:upstream 指向原作者的 repoorigin 指向 forked repo更新方法# 切换到 master 分支git checkout master# 拉取原作者的 repogit pull upstream master:master# 更新 forked repogit push origin master:master# 更新 forked repo 的远端分支git remote update –prunePull Request 追踪特性pull request 会追踪发起它的远端分支(简称 PR 分支,本地副本被称为“本地PR 分支”),除非已被 merge 或者处于 close 状态。如果 pull request 被 merge,PR 分支可以被原作者删除。如果 pull request 被 close,PR 分支可以被原作者删除。一旦删除,该 pull request 就不能再被 reopen。预览 Pull Request 合并后的状态首先,更新 repo。其次,搭建预览现场。此时完全不用担心 conflict(除非 GitHub 网页已经指出)。git checkout -b [预览分支]git pull [发起 repo 的 URL] [发起分支]然后,预览(一般是测试)。最后,清理预览现场。git checkout mastergit branch -D [预览分支]解决 Pull Request 冲突GitHub 的 pull request 页面指出 PR 冲突,可用下列方法解决:首先,更新 repo。然后,将 master 分支合并到本地 PR 分支。此时必然发生 conflict,解决并新建 commit。建议使用 GitHub Desktop 或 IDE 来执行该步骤。最后,push 本地 PR 发起分支。此时,GitHub 上的 pull request 会追加 commit,并指出冲突已消除。Pull Request 与 IssueGitHub 中 pull request 和 issue 共用一套编号。可在页面末尾添加的 comment,称为 issue comment。相关的 API 都在这里。如果 commit message 包含fix / fixes / fixed / close / closes / closed / resolve / resolves / resolved等关键字加上#编号,一旦 commit 被加入 repo,相应的 issue 就会被 close。 ...

March 8, 2019 · 1 min · jiezi

开发函数计算的正确姿势——使用 brotli 压缩大文件

大文件问题函数计算对上传的 zip 代码包尺寸限制为 50M。某些场景中代码包中会超过这一限制,比如二进制 serverless-chrome 经过一番裁剪以后 ZIP 压缩包的体积为 43.4M,类似的还有 liboffice ,此外常见的还有机器学习训练的模型文件。目前解决大文件问题有三种方法采用更高压缩比的算法,比如本文介绍的 brotli 算法采用 OSS 运行时下载采用 NAS 文件共享简单的比较一下这三种方法的优劣方法优点缺点高密度压缩发布简单,启动最快上传代码包较慢;要写解压代码;大小受限制不超过 50 MOSS下载解压后文件不超过 512 M需要预先上传至 OSS;要写下载和解压代码,大概 50M/s 的下载速度NAS文件大小没有限制,无需压缩需要预先上传至 NAS;VPC 环境有冷启动时延(~5s)正常情况下如果代码包能控制在 50M 以下启动较快。而且工程上也比较简单,数据和代码放在一起,不需要额外的写脚本去同步更新 OSS 或者 NAS。压缩算法Brotli 是 Google 工程师开发的开源压缩算法,目前已经被新版的主流浏览器支持,作为 HTTP 传输的压缩算法。下面是在网上找到的关于 Brotli 和其他常见压缩算法对比基准测试。从上面三幅图我们可以看出:相比于 gzip、xz 和 bz2,brotli 有最高的压缩比,接近于 gzip 的解压速度,以及最慢的压缩速度。然而在我们的场景对于压缩慢这一缺点不敏感,压缩任务只要在开发准备物料的阶段执行一次就好了。制作压缩文件下面我先介绍一下如何制作压缩文件。下面的代码和用例都来自于项目 packed-selenium-java-example 。安装 brotli 命令Mac 用户brew install brotliWindows 用户可以去这个界面下载,https://github.com/google/brotli/releases打包并压缩打包前两个文件大小分别为 7.5M 和 97M╭─ ~/D/test1[◷ 18:15:21]╰─ lltotal 213840-rwxr-xr-x 1 vangie staff 7.5M 3 5 11:13 chromedriver-rwxr-xr-x 1 vangie staff 97M 1 25 2018 headless-chromium使用 GZip 打包并压缩,大小为 44 M。╭─ ~/D/test1[◷ 18:15:33]╰─ tar -czvf chromedriver.tar chromedriver headless-chromiuma chromedrivera headless-chromium╭─ ~/D/test1[◷ 18:16:41]╰─ lltotal 306216-rwxr-xr-x 1 vangie staff 7.5M 3 5 11:13 chromedriver-rw-r–r– 1 vangie staff 44M 3 6 18:16 chromedriver.tar-rwxr-xr-x 1 vangie staff 97M 1 25 2018 headless-chromiumtar 去掉 z 选项再打包一遍,大小为 104M╭─ ~/D/test1[◷ 18:16:42]╰─ tar -cvf chromedriver.tar chromedriver headless-chromiuma chromedrivera headless-chromium╭─ ~/D/test1[◷ 18:17:06]╰─ lltotal 443232-rwxr-xr-x 1 vangie staff 7.5M 3 5 11:13 chromedriver-rw-r–r– 1 vangie staff 104M 3 6 18:17 chromedriver.tar-rwxr-xr-x 1 vangie staff 97M 1 25 2018 headless-chromium压缩后的大小为 33M,相比 Gzip 的 44M 小了不少。耗时也非常的感人 6 分 18 秒,Gzip 只要 5 秒。╭─ ~/D/test1[◷ 18:17:08]╰─ time brotli -q 11 -j -f chromedriver.tarbrotli -q 11 -j -f chromedriver.tar 375.39s user 1.66s system 99% cpu 6:18.21 total╭─ ~/D/test1[◷ 18:24:23]╰─ lltotal 281552-rwxr-xr-x 1 vangie staff 7.5M 3 5 11:13 chromedriver-rw-r–r– 1 vangie staff 33M 3 6 18:17 chromedriver.tar.br-rwxr-xr-x 1 vangie staff 97M 1 25 2018 headless-chromium运行时解压缩下面以 java maven 项目为例添加解压依赖包<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-compress</artifactId> <version>1.18</version></dependency><dependency> <groupId>org.brotli</groupId> <artifactId>dec</artifactId> <version>0.1.2</version></dependency>commons-compress 是 apache 提供的解压缩工具包,对于各种压缩算法提供一致的抽象接口,其中对于 brotli 算法只支持解压,这里足够了。org.brotli:dec 包是 Google 提供的 brotli 解压算法的底层实现。实现 initialize 方法public class ChromeDemo implements FunctionInitializer { public void initialize(Context context) throws IOException { Instant start = Instant.now(); try (TarArchiveInputStream in = new TarArchiveInputStream( new BrotliCompressorInputStream( new BufferedInputStream( new FileInputStream(“chromedriver.tar.br”))))) { TarArchiveEntry entry; while ((entry = in.getNextTarEntry()) != null) { if (entry.isDirectory()) { continue; } File file = new File("/tmp/bin", entry.getName()); File parent = file.getParentFile(); if (!parent.exists()) { parent.mkdirs(); } System.out.println(“extract file to " + file.getAbsolutePath()); try (FileOutputStream out = new FileOutputStream(file)) { IOUtils.copy(in, out); } Files.setPosixFilePermissions(file.getCanonicalFile().toPath(), getPosixFilePermission(entry.getMode())); } } Instant finish = Instant.now(); long timeElapsed = Duration.between(start, finish).toMillis(); System.out.println(“Extract binary elapsed: " + timeElapsed + “ms”); }}实现 FunctionInitializer 接口的 initialize 方法。解压过程刚开始是四层嵌套流,作用分别如下:FileInputStream 读取文件BufferedInputStream 提供缓存,介绍系统调用带来的上下文切换,提示读取的速度BrotliCompressorInputStream 对字节流进行解码TarArchiveInputStream 把 tar 包里的文件逐个解出来然后 Files.setPosixFilePermissions 的作用是还原 tar 包中文件的权限。代码太长此处略去,参阅 packed-selenium-java-exampleInstant start = Instant.now();…Instant finish = Instant.now();long timeElapsed = Duration.between(start, finish).toMillis();System.out.println(“Extract binary elapsed: " + timeElapsed + “ms”);上面的代码段会打印出解压的耗时,真实执行大概在 3.7 s 左右。最后不要忘记在 template.yml 里配置上 Initializer 和 InitializationTimeout参考阅读https://www.opencpu.org/posts/brotli-benchmarks/https://github.com/vangie/packed-selenium-java-example本文作者:倚贤阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

March 8, 2019 · 2 min · jiezi

D2 日报 2019年 03月 08日

新闻➡️ Introducing draft pull requests 非中文 GitHub 新增 Draft Pull Request 协作流程 github.blog开源项目➡️ rocky/python-uncompyle6 非中文 watch 39 star 1022 fork 127 Python 反编译工具,可以将 Python 字节码 pyc 文件反编译回源码 py 文件 github.com➡️ sharkdp/hexyl 非中文 watch 59 star 4080 fork 102 一个命令行的文件十六进制查看工具。它能够以不同的颜色,表示不同的字节内容 github.com➡️ moment / luxon watch 104 star 7874 fork 306 在Javascript中处理日期和时间的库 github.com➡️ ccyyycy/ycy watch 102 star 933 fork 121 欢迎大家!hello ycy github.com➡️ FrankFang/best-chinese-front-end-blogs watch 275 star 2312 fork 448 收集优质的中文前端博客 github.com➡️ alibaba/coobjc 非中文 watch 72 star 2578 fork 316 基于 Apache 2.0 协议的协程开发框架 coobjc。coobjc是为iOS平台打造的开源协程开发框架,支持Objective-C和Swift,同时提供了cokit库为Foundation和UIKit中的部分API提供了协程化支持 github.com分享➡️ 避免那些可恶的 “cannot read property of undefined” 错误 juejin.im➡️ 腾讯大厦与我有个约定(面试精华帖) 作者是位被代码迷了眼的好编辑 juejin.im➡️ 宕机的阿里云们正在杀死运维? www.infoq.cn网站➡️ Inpainting 非中文 nvidia 官方的在线图像修复,自动生成图像缺失的部分 www.nvidia.com➡️ Puffer 非中文 斯坦福大学的一个视频算法实验项目,可以免费观看美国的电视直播,画质1080P puffer.stanford.edu工具➡️ Emun C++ 代码网页 IDE emun.ro➡️ MakeCode Arcade 非中文 一个基于 Web 的初学者友好的代码编辑器,用于为 Web 和专用硬件创建复古的街机游戏。你可以很容易地制作一款游戏,然后在浏览器里玩,也可以在专用硬件上玩 makecode.com更优雅地阅读阅读我们精心排版之后的页面 《D2 日报 2019年 03月 08日》往期回顾官网关于 D2 DailyD2 日报是开源组织 D2 Projects 下的一个公益新闻类开源项目。宗旨是一切资源免费且开源,但是希望每个人既是读者也是分享者,如果有足够的能力,你也可以成为开发者。请在每天闲(mo)暇(yu)时光享受日报带来的丰富知识,也请在自己发现优质资源时随手分享给大家。???????? 分享你的发现和创造 投稿/提交在哪里可以看到日报官网Github掘金即刻Segmentfault简书开源中国CSDN ...

March 8, 2019 · 1 min · jiezi

jSearch(聚搜) v0.5.0 发布,多项更新和体验优化

更新日志:jSearch-v0.5.0新增:站点搜索的默认搜索(即搜索词为空时)修改为检索最近一天的内容(即 可以了解所关注网站的最新动态);新增页面横向滚动方案(alt+滚轮,左键+滚轮,左右方向键);新增通用设置:支持快捷搜索框(jBar)热键设置;页面横向滚动设置;新增划词搜索(实验功能,默认未开启,可在设置中自行开启);新增列表载入动画;优化:修改 google 结果链接为新页面打开;修复搜索词带特殊符号引发的问题;修复 google 结果展示问题;优化 Windows 滚动条样式;修复第一页内容高度不够时无法翻页问题;已经其他细微的优化调整;下载:https://github.com/dubox/jSea…https://gitee.com/dubox/jSear...jSearch(聚搜)是一款专注内容的chrome搜索扩展,一次搜索聚合多平台内容; 帮你开启新世界大门。just Search it!

March 8, 2019 · 1 min · jiezi

git配置多个ssh key

在日常工作中公司会用到gitlab托管代码,但是自己的一些项目会放到github上,这时就需要为每个托管平台设置ssh key。下面是具体操作:1.生成ssh-key进入到.ssh目录下,输入以下命令生成ssh-key,your_email@example.com填入自己的邮箱ssh-keygen -t rsa -C “your_email@example.com"此时第一次输入的文件名,如果直接按回车会自动生成私钥和公钥:id_rsa、id_rsa.pub;第二次和第三次是密码和确认密码,此时直接回车即可。2.将ssh-key添加到ssh agentssh-add 私钥文件名如果执行ssh-add时提示”Could not open a connection to your authentication agent”可以先执行命令:ssh-agent bash然后在重新运行ssh-add命令3.修改配置文件将不同的账号对应的不同的ssh key 和不同的远程服务器关联起来,这个配置是在config下配置的(如果没有config可以自己新建)Host github.com HostName github.com User git IdentityFile ~/.ssh/id_rsa_aHost git.gitlab.net HostName git.gitlab.net User git IdentityFile ~/.ssh/id_rsa_gitlab其中,Host和HostName填写git服务器的域名。IdentityFile指定私钥的路径。未加入配置文件的网站会自动应用id_rsa4.将id_rsa.pub 上传到GitHub或GitLab上测试下是否成功ssh -T git@gitlab.com出现welcome to gitlab!就代表连接成功了现在你的多个ssh key就可以使用了

March 7, 2019 · 1 min · jiezi

D2 日报 2019年3月7日

新闻➡️ Vant 1.6.8 发布,有赞轻量级移动端 Vue 组件库 www.oschina.net➡️ 换芯后的 Edge 浏览器 UI 首曝光,还是熟悉的味道? - 开源中国 www.oschina.net➡️ 阿里宣布开源Flutter应用框架Fish Redux www.infoq.cn开源项目➡️ donnemartin/gitsome 非中文 watch 133 star 6282 fork 325 一个 Git / GitHub 的命令行客户端,提供强大的自动补全功能 github.com➡️ rrweb-io/rrweb 非中文 watch 67 star 4131 fork 172 将网页操作录制成可复现的脚本 github.com➡️ Pagedraw/pagedraw 非中文 watch 45 star 1878 fork 181 一个 UI 原型设计的桌面软件,可以输出 JSX 代码 github.com➡️ OlleLinderos/FP-Glossary 非中文 watch 6 star 67 fork 2 一个 Chrome 浏览器插件,每次打开一个空白页,会显示一个函数式编程的概念 github.com➡️ NationalSecurityAgency/ghidra 非中文 watch 212 star 2760 fork 242 一个由美国国家安全局研究理事会(NSA)创建和维护的软件逆向工程(SRE)框架。该框架包括一套功能齐全的软件分析工具,使用户能够在各种平台上分析编译后的代码 github.com➡️ alibaba/fish-redux 非中文 watch 60 star 1510 fork 163 闲鱼技术开源的Flutter框架 github.com➡️ codercom/code-server 非中文 watch 40 star 1265 fork 42 在线版的 VSCode,支持大部分的 VSCode 插件 github.com➡️ lifei6671/NeteaseCloudMusicFlac watch 6 star 74 fork 14 根据网易云音乐的歌单, 下载flac无损音乐到本地 github.com➡️ aceakash/string-similarity 非中文 watch 20 star 1449 fork 48 找出两个字符串之间的相似程度 github.com➡️ didi/rdebug 非中文 watch 14 star 244 fork 27 滴滴开源支撑业务代码重构工具 github.com➡️ gengchen528/wechatBot watch 8 star 139 fork 30 微信每日说,每日自动发送微信消息 github.com分享➡️ 不可思议的纯 CSS 实现鼠标跟随效果 juejin.im➡️ 如何建立一个可持续激励优质内容的社区 juejin.im➡️ 了解这12个概念,让你的JavaScript水平更上一层楼 www.infoq.cn➡️ 免费中文字体收集 免费字体了解一下 zenozeng.github.io网站➡️ 网页修仙传 louisalflame.github.io➡️ Project Showcase - Create a portfolio for your projects 非中文 根据你的 GitHub 个人项目,生成一张个人介绍页面 projectshowcase.me➡️ explainshell.com - match command-line arguments to their help text 非中文 Bash 命令的可视化解释工具。遇到复杂的 Bash 命令,可以输入到这个网站,查看该命令的解释 www.explainshell.com➡️ Wayback Machine Downloader. Online Website Downloader. CMS converter. 非中文 该工具可以用来从 Achive.org 的 Wayback Machine 里面,下载某个网站在指定日期的所有网页 en.archivarix.com工具➡️ Neulana/copy2clipboard watch 0 star 34 fork 0 ????a tampermonkey script to copy code anywhere. github.com➡️ sentialx/multrin 非中文 watch 13 star 372 fork 11 Multrin 是一个跨平台的软件,使用 Electron 构建。你可以把应用程序放到 Multrin 上,然后就可以在在选项卡中组织多个应用程序 github.com➡️ Coder 非中文 在线 vscode 编辑器 coder.com更优雅地阅读阅读我们精心排版之后的页面 《D2 日报 2019 年 03 月 07 日》往期回顾官网关于 D2 DailyD2 日报是开源组织 D2 Projects 下的一个公益新闻类开源项目。宗旨是一切资源免费且开源,但是希望每个人既是读者也是分享者,如果有足够的能力,你也可以成为开发者。请在每天闲(mo)暇(yu)时光享受日报带来的丰富知识,也请在自己发现优质资源时随手分享给大家。???????? 分享你的发现和创造 投稿/提交在哪里可以看到日报官网掘金专栏Github 仓库即刻 ...

March 7, 2019 · 2 min · jiezi

如何在GitHub上创建个人博客

原文地址:https://nolon.xyzGitHub给用户提供了一些储存空间,可以很好的发布我们的项目,利用GitHub pages可以快速简便的搭建一个个人博客,并且省去了注册域名和购买服务器这一步骤。今天我就来给大家详细介绍一下如何利用GitHub pages+Hexo搭建个人博客。GitHub上的准备https://github.com/ 这是GitHub的首页,进去之后点击右上角的sign up进行注册,注册成功后你就拥有了自己的代码仓库在Github首页右上角头像左侧加号点选择 New repositor(新存储库)或点击这里进行创建一个仓库.进入仓库点击右边的设置找到GitHub pages这一块,会提示分配给你的域名,都是用户名.github.io下载GitHub客户端,根据你的系统自己选择下载点击前往GitHub下载下载好之后,登录你的账号,然后把GitHub上的仓库克隆到本地使用Hexo使用Hexo之前需要安装Node.js、Git安装Hexo选择一个磁盘然后新建一个文件夹,右键选择Git bash打开之后就是这样,输入以下命令npm install hexo-cli -g hexo init #初始化网站 npm install hexo g #生成或 hexo generate hexo s #启动本地服务器 或者 hexo server,这一步之后就可以通过http://localhost:4000 查看了添加主题安装主题(yilia主题):hexo cleangit clone https://github.com/litten/hexo-theme-yilia.git themes/yilia 启动主题找到目录下的_config.yml 文件,打开找到 theme:属性并设置为yilia更新主题cd themes/yiliagit pullhexo ghexo s此时刷新http://localhost:4000/页面就能看到新的主题了.使用Hexo deploy部署到github还是编辑根目录下_config.yml文件deploy: type: git repo: git@github.com:YANH66/yanh66.github.io #这里的网址填你自己的 branch: master 保存后需要提前安装一个扩展:npm install hexo-deployer-git –save接下来就是将Hexo部署到我们的Github仓库上部署到GitHub检查SSH keys的设置在Git bash中输入以下命令cd ~/.sshls#此时会显示一些文件mkdir key_backupcp id_rsa* key_backuprm id_rsa* #以上三步为备份和移除原来的SSH key设置ssh-keygen -t rsa -C “邮件地址@youremail.com” #生成新的key文件,邮箱地址填你的Github地址#Enter file in which to save the key (/Users/your_user_directory/.ssh/id_rsa):<回车就好>#接下来会让你输入密码然后会看到成功的画面添加SSH keys到GitHub点击右上角的头像,从下拉菜单里找到设置,然后点开在设置里找到SSH and GPG keys从本地电脑里找到隐藏文件.ssh 打开之后找到id.rsa.pub 用记事本方式打开之后复制粘贴到key中到了这就可以测试一下是否成功了:ssh -T git@github.com#之后会要你输入yes/no,输入yes就好了。设置你的账号信息:git config –global user.name “你的名字” #真实名字不是github用户名git config –global user.email “邮箱@邮箱.com” #github邮箱部署到GitHubhexo d这时再刷新 username.github.io 就可以看到你的博客了。 ...

March 6, 2019 · 1 min · jiezi

Github contributions/Git提交了commit后github个人主页中没有活动记录

本篇文章要解决的问题是: 本地git客户端和github账户邮箱不一致导致提交的commit不能够显示在github个人主页的contributions中4个步骤分别是:1. 将git的email修改成和github的邮箱对应修改邮箱地址:git config –global user.email “eamil@example.com"查看当前邮箱:git config user.email2. 将git中提交的的commit修改复制到git中执行:git config alias.change-commits ‘!’“f() { VAR=$1; OLD=$2; NEW=$3; shift 3; git filter-branch –env-filter "if [[ \"$`echo $VAR`\" = ‘$OLD’ ]]; then export $VAR=’$NEW’; fi" $@; }; f “然后执行下面这条命令,把命令中的邮箱地址换成你自己的: (HEAD3的意思是将最近提交的3次commit的邮箱设置成newEmail) git change-commits GIT_AUTHOR_EMAIL “oldEmail@example.com” “newEmail@example.com” HEAD3..HEAD3. 重新拉取代码并提交即可看到效果4. 删除修改commit时的备份(不是必须的)执行命令: git update-ref -d refs/original/refs/heads/master参考:https://stackoverflow.com/que…https://www.cnblogs.com/wyhli...http://lincolnge.github.io/pr…

March 6, 2019 · 1 min · jiezi

github个人博客主题优化之next

前言最近博客更新了一下主题,由之前的yilia主题更新成集成功能更齐全的next。借此也把搭建博客和优化主题的过程记录一下。1 搭建博客1-1 搭建环境Node.js下载安装: https://nodejs.org/en/download/git下载安装:https://git-scm.com/downloadshexo下载安装:$ npm install -g hexo-cli搭建本地博客在桌面新建test目录,进入test目录右键选择git Bash Here在命令行界面初始化hexo(这里以test文件夹为例,文中后续都是以test文件夹作为根目录)$ hexo init更新下载依赖包$ hexo install启动本地服务$ hexo s浏览器访问http://localhost:4000,可以看到博客已经搭建在本地。1-2 部署到github上创建github账号:https://github.com(注册的邮箱一定要验证)新建一个名为<github用户名>.github.io的仓库,比如说,如果你的github用户名是mygithub,那么你就新建mygithub.github.io的仓库。安装hexo-deployer-git插件。在命令行(即Git Bash)运行以下命令即可:$ npm install hexo-deployer-git –save配置ssh检查是否有ssh$ cd ~/. ssh #检查本机已存在的ssh密钥(No such file or directory 说明你是第一次使用git。)生成ssh$ ssh-keygen -t rsa -C “邮件地址”(注册github时的邮箱)然后连续3次回车,复制密钥文件内容(路径形如C:\Users\Administrator.ssh\id_rsa.pub),粘贴到New SSH Key即可。打开你的github主页,进入个人设置 -> SSH and GPG keys -> New SSH key:测试是否成功配置ssh$ ssh -T git@github.com提示 Are you sure you want to continue connecting (yes/no)?,输入yes返回 “You’ve successfully authenticated” 即成功:修改_config.yml(在test目录下)。文件末尾添加下面代码:# Deployment## Docs: https://hexo.io/docs/deployment.htmldeploy: type: git repo: git@github.com:<Github账号名称>/<Github账号名称>.github.io.git branch: master推送到GithubPages。在命令行(即Git Bash)依次输入以下命令, 返回 INFO Deploy done: git 即成功推送:$ hexo d -g至此,Hexo博客已经搭建在GithubPages, 域名为https://<Github账号名称>.github.io2 主题选择和优化2-1 主题选择这里我选择的是next主题,在/test目录下载主题文件$ git clone https://github.com/iissnan/hexo-theme-next themes/next修改/test目录下的_config.yml文件,更改theme字段,为主题文件夹的名称$ theme: next2-2 主题基本配置2-2-1 设置 语言修改/test目录下的_config.yml文件,选择语言language: zh-Hans(默认为英文,zh-Hans为中文简体)2-2-2 设置 作者昵称/test目录下的_config.yml文件,设置author为你的昵称。author : <你的昵称>2-2-3 设置 站点描述修改/test目录下的_config.yml文件,设置description字段为你的站点描述。description : 站点描述可以是你喜欢的一句签名:)2-2-4 设置 侧边栏社交链接修改/test目录下的_config.yml文件,设置social字段。social: GitHub: https://github.com/your-user-name || github Twitter: https://twitter.com/your-user-name || twitter Weibo: http://weibo.com/your-user-name || weibo如果只想显示图标可以设置social_icons字段social_icons: enable: true icons_only: true transition: true2-2-5 设置「背景动画」修改/test目录下的_config.yml文件,有4款背景动画,选择你喜欢的设置为true即可# Canvas-nestcanvas_nest: true# three_wavesthree_waves: false# canvas_linescanvas_lines: false# canvas_spherecanvas_sphere: false2-2-6 设置「动画效果」修改/test目录下的_config.yml文件,设置motion字段。motion enable: true2-2-7 选择 Schemenext提供了几种主题模式可供切换,选择一款你喜欢的/test/themes/next目录下的_config.yml文件,全局查找scheme,选择一款打开注释#scheme: Muse#scheme: Mist#scheme: Piscesscheme: Gemini2-2-8 配置 菜单栏修改/test/themes/next目录下的_config.yml文件,menu关键字下面的配置就是菜单栏,next的默认菜单配置一般来说我们都会有自己的定制。给出我的配置以供参考menu: home: / || home about: /about/ || user tags: /tags/ || tags categories: /categories/ || th archives: /archives/ || archive music: /music/ || music|| 后面的内容为菜单栏的图标icon,就是Font Awesome 图标名字2-2-9 配置优化 用户图像修改/test/themes/next目录下的_config.yml文件,设置avatar 为一张图片,把你喜欢的图片下载并放到 /test/themes/next/source/images文件夹中avatar: /images/<图片名字>.jpg找到主题配置文件:/test/themes/next/source/css/_common/components/sidebar/sidebar-author.styl加入下面代码:.site-author-image { display: block; margin: 0 auto; padding: $site-author-image-padding; max-width: $site-author-image-width; height: $site-author-image-height; border: $site-author-image-border-width solid $site-author-image-border-color; /* 头像圆形 / border-radius: 80px; -webkit-border-radius: 80px; -moz-border-radius: 80px; box-shadow: inset 0 -1px 0 #333sf; / 设置循环动画 [animation: (play)动画名称 (2s)动画播放时长单位秒或微秒 (ase-out)动画播放的速度曲线为以低速结束 (1s)等待1秒然后开始动画 (1)动画播放次数(infinite为循环播放) ]/ / 鼠标经过头像旋转360度 / -webkit-transition: -webkit-transform 1.0s ease-out; -moz-transition: -moz-transform 1.0s ease-out; transition: transform 1.0s ease-out;}img:hover { / 鼠标经过停止头像旋转 -webkit-animation-play-state:paused; animation-play-state:paused;/ / 鼠标经过头像旋转360度 / -webkit-transform: rotateZ(360deg); -moz-transform: rotateZ(360deg); transform: rotateZ(360deg);}/ Z 轴旋转动画 /@-webkit-keyframes play { 0% { -webkit-transform: rotateZ(0deg); } 100% { -webkit-transform: rotateZ(-360deg); }}@-moz-keyframes play { 0% { -moz-transform: rotateZ(0deg); } 100% { -moz-transform: rotateZ(-360deg); }}@keyframes play { 0% { transform: rotateZ(0deg); } 100% { transform: rotateZ(-360deg); }}2-2-10 添加「标签」页面在/test/source目录下新建tags文件夹,在/test/source/tags下新建index.md,内容为—title: 标签type: “tags”—2-2-11 添加「分类」页面在/test/source目录下新建categories文件夹,在/test/source/categories下新建index.md,内容为—title: 标签type: “categories”—2-2-12 设置 字体由于引用国外字体镜像较慢,所以nexT 开放了 5 个特定范围的字体设定来解决问题。修改/test/themes/next目录下的_config.yml文件。找到font关键字,替换它下面的内容为font: enable: true # 外链字体库地址,例如 //fonts.googleapis.com (默认值) host: # 全局字体,应用在 body 元素上 global: external: true family: Monda # 标题字体 (h1, h2, h3, h4, h5, h6) headings: external: true family: Roboto Slab # 文章字体 posts: external: true family: # Logo 字体 logo: external: true family: Lobster Two size: 24 # 代码字体,应用于 code 以及代码块 codes: external: true family: PT Mono2-2-13 设置代码高亮修改/test/themes/next目录下的_config.yml文件。修改highlight_theme关键字,共有5款主题供你选择highlight_theme: normal/night/night blue/night bright/night eighties2-2-14 设置友情链接修改/test/themes/next目录下的_config.yml文件。找到Blog rolls进行设置# Blog rollslinks_icon: link (icon图标)links_title: 友情链接 (文字描述)#links_layout: block (设置链接是一行展示一条)links_layout: inline (设置链接是一行展示多条)links: test: http://macshuo.com/ (链接的名字和地址)2-2-15 设置博客置顶安装插件$ npm uninstall hexo-generator-index –save$ npm install hexo-generator-index-pin-top –save设置置顶标志:打开/test/themes//layout/_macro/post.swig在<div class=“post-meta”>下方插入代码:{% if post.top %} <i class=“fa fa-thumb-tack”></i> <font color=808080>置顶</font> <span class=“post-meta-divider”>|</span>{% endif %}然后在需要置顶的文章的Front-matter中加上top即可:—title: 2018date: 2018-10-25 16:10:03top: 100—2-2-16 设置和优化打赏点击进入在线生成二维码生成自己的微信和支付宝二维码。下载下来保存到/test/themes/next/source/images中修改/test/themes/next目录下的_config.yml文件。找到Reward关键字进行配置-Rewardreward_comment: 谢谢打赏,好人一生平安 (打赏的描述)wechatpay: /images/weixin.png (微信二维码)alipay: /images/zhifubao.png (支付宝二维码)移除打赏抖动,修改/test/themes/next/source/css/_common/components/post/post-reward.styl,注释以下代码/* 注释文字闪动函数#wechat:hover p{ animation: roll 0.1s infinite linear; -webkit-animation: roll 0.1s infinite linear; -moz-animation: roll 0.1s infinite linear;}#alipay:hover p{ animation: roll 0.1s infinite linear; -webkit-animation: roll 0.1s infinite linear; -moz-animation: roll 0.1s infinite linear;}#bitcoin:hover p { animation: roll 0.1s infinite linear; -webkit-animation: roll 0.1s infinite linear; -moz-animation: roll 0.1s infinite linear;}/2-2-17 每篇文章后添加结束标语新建文件,在/test/themes/next/layout/_macro中新建passage-end-tag.swig文件,添加代码至该文件中:<div> {% if not is_index %} <div style=“text-align:center;color: #ccc;font-size: 15px;letter-spacing: 5px;margin-top: 35px;">———-本文结束<i class=“fa fa-paw”></i>感谢您的阅读———–</div> {% endif %}</div>修改post.swig,打开/test/themes/next/layout/_macro/post.swig文件,在post-body后,post-footer前,添加下面内容:<div> {% if not is_index %} {% include ‘passage-end-tag.swig’ %} {% endif %}</div>修改_config,打开/test/themes/next/下的_config.yml,在末尾添加:# 文章末尾添加“本文结束”标记passage_end_tag: enabled: true2-2-18 添加转载协议声明打开/test/themes/next/下的_config.yml,找到Declare license on posts,配置# Declare license on postspost_copyright: enable: true license: CC BY-NC-SA 3.0 license_url: https://creativecommons.org/licenses/by-nc-sa/3.0/打开/test下的_config.yml,找到URL,配置# URLurl: <你的github博客地址>2-3 主题优化2-3-1 实现fork me on github选择样式GitHub Ribbons:https://github.blog/2008-12-1…修改图片跳转链接,将<a href=“https://github.com/you">中的链接换为自己Github链接打开/test/themes/next/layout/_layout.swig 文件,把代码复制到<div class=“headband”></div>下面。<a href=“https://github.com/tmgycsz/tmgycsz.github.io" class=“forkme” target="_blank”> <img style=“position: absolute; right: 0px;” width=“149” height=“149” src=“https://github.blog/wp-content/uploads/2008/12/forkme_right_white_ffffff.png?resize=149%2C149" class=“attachment-full size-full” alt=“Fork me on GitHub” data-recalc-dims=“1”></a>2-3-2 添加点击爱心效果在/test/themes/next/source/js/src文件夹下创建clicklove.js,添加代码:!function(e,t,a){function n(){c(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: ‘’;width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}”),o(),r()}function r(){for(var e=0;e<d.length;e++)d[e].alpha<=0?(t.body.removeChild(d[e].el),d.splice(e,1)):(d[e].y–,d[e].scale+=.004,d[e].alpha-=.013,d[e].el.style.cssText=“left:"+d[e].x+“px;top:"+d[e].y+“px;opacity:"+d[e].alpha+";transform:scale("+d[e].scale+”,"+d[e].scale+”) rotate(45deg);background:"+d[e].color+";z-index:99999”);requestAnimationFrame(r)}function o(){var t=“function”==typeof e.onclick&&e.onclick;e.onclick=function(e){t&&t(),i(e)}}function i(e){var a=t.createElement(“div”);a.className=“heart”,d.push({el:a,x:e.clientX-5,y:e.clientY-5,scale:1,alpha:1,color:s()}),t.body.appendChild(a)}function c(e){var a=t.createElement(“style”);a.type=“text/css”;try{a.appendChild(t.createTextNode(e))}catch(t){a.styleSheet.cssText=e}t.getElementsByTagName(“head”)[0].appendChild(a)}function s(){return"rgb("+~~(255Math.random())+”,"+(255*Math.random())+”,"+(255*Math.random())+")"}var d=[];e.requestAnimationFrame=function(){return e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)}}(),n()}(window,document);在/test/themes/next/layout/_layout.swig文件末尾添加:<!– 页面点击小红心 –><script type=“text/javascript” src="/js/src/clicklove.js"></script>2-3-3 添加网页崩溃欺骗特效在/test/themes/next/source/js/src文件夹下创建crash_cheat.js,添加代码:<!–崩溃欺骗–> var OriginTitle = document.title; var titleTime; document.addEventListener(‘visibilitychange’, function () { if (document.hidden) { document.title = ‘╭(°A°)╮ 页面崩溃啦 ~'; clearTimeout(titleTime); } else { document.title = '(&gt;&lt;*) 噫又好了~' + OriginTitle; titleTime = setTimeout(function () { document.title = OriginTitle; }, 2000); } });在/test/themes/next/layout/_layout.swig文件末尾添加:&lt;!--崩溃欺骗--&gt;&lt;script type="text/javascript" src="/js/src/crash_cheat.js"&gt;&lt;/script&gt;2-3-4 添加访问不蒜子统计打开/test/themes/next/下的_config.yml,找到busuanzi_count,配置busuanzi_count: enable: true total_visitors: true (总的访客人数) total_visitors_icon: user (访客人数图标) total_views: true (总的访问量) total_views_icon: eye (访问量图标) post_views: true (文章总阅读次数) post_views_icon: eye(文章总阅读图标)2-3-5 添加评论系统Valine请先注册LeanCloud, 注册成功进入应用列表页面,创建应用。进入刚刚创建的应用,选择左下角的设置&gt;应用Key,然后就能看到你的APP ID和APP Key了。打开/test/themes/next/下的_config.yml,找到valine,配置valine: enable: true appid: dHAGLgRYVcYtd02p3WpBLKiQ-gzGzoHsz appkey: DtL0hVwsWFyrDdw4QPWhg9zR notify: false (邮件提醒,回复是否发送到邮箱) verify: false (回复是否需要验证) placeholder: Just go go (回复框占位符) avatar: mm # gravatar style guest_info: nick,mail,link (评论可以填写的信息) pageSize: 10 # (每页显示多少条评论)2-3-6 添加文章字数统计和预计阅读时间打开/test/themes/next/下的_config.yml,找到post_wordcount,配置post_wordcount item_text: true wordcount: true min2read: true totalcount: true separated_meta: true2-3-7 实现本地搜索/test目录下下载插件$ npm install hexo-generator-searchdb –save修改/test下的_config.yml,新增以下内容到任意位置:search: path: search.xml field: post format: html limit: 10000打开/test/themes/next/下的_config.yml,找到post_wordcount,配置local_search: enable: true trigger: auto (搜索方式:是输入的时候搜索还是回车或搜索键搜索) # show top n results per article, show all results by setting to -1 top_n_per_article: 1文中的优化方案来自next官方使用文档以及各路大神的贡献,我这里只是做个总结。我的blog地址: https://tmgycsz.github.io/参考文档next文档: http://theme-next.iissnan.com/还有其它优化,持续更新中。。。 ...

March 4, 2019 · 4 min · jiezi

Pandas之旅(一): 让我们把基础知识一次撸完,申精干货

为什么你需要pandas大家好,今天想和大家分享一下有关pandas的学习新的,我因工作需要,从去年12月开始接触这个非常好用的包,到现在为止也是算是熟悉了一些,因此发现了它的强大之处,特意想要和朋友们分享,特别是如果你每天和excel打交道,总是需要编写一些vba函数或者对行列进行groupby啊,merge,join啊之类的,相信我,pandas会让你解脱的。好啦,闲话少说,这篇文章的基础是假设你已经大概听说过了pandas的一些概念和用途,如果还大体上不太清楚的朋友们,可以去百度一下相关基础介绍,本分主要分成四个部分:从Dataframe说起 : 简单了解Df这种数据结构,了解如何创建一个DfDataframe基础操作 :基于行,列,index选取数据,新增数据,删除数据Pandas 读取 / 导出数据: 了解如何对excel,csv,tsv等常见文件进行读取并导出总结: 精华部分,为大家总结一些非常实用的一些方法,并附带源码 ipynb以及py文件提供下载1. 从Dataframe说起首先,让我们明确一点,pandas这个包是在numpy的基础上得到的,因此可能有的朋友会有疑问,要不要先学学numpy,我的个人建议是真的不太需要,因为大多数的情况下基本用不到,当然,如果你处理的是科学实验类型的数据的话,当我没说,我这里的应用场景主要是一般类型的常见数据,比如:你是销售经理,经常需要汇总各地区的销售情况你在银行工作,不可避免的需要和数字,excel打交道你每天有很多重复的工作,比如备份,计算两表合并,分组,聚类等等。。。。。。这种情况下,学习pandas会非常有用,这里我们说的数据都是二维的table,在pandas中也称作dataframe。pandas中其实一共有三种类型的常见数据:数据结构维度说明Series1类似list,一维数组Data Frames2最常见的二维数据结构,excel,sql的表就是这个Panel3用的很少,三维结构pandas主要包括三类数据结构,分别是:Series:一维数组,与Numpy中的一维array类似。二者与Python基本的数据结构List也很相近,其区别是:List中的元素可以是不同的数据类型,而Array和Series中则只允许存储相同的数据类型,这样可以更有效的使用内存,提高运算效率。DataFrame:二维的表格型数据结构。很多功能与R中的data.frame类似。可以将DataFrame理解为Series的容器。以下的内容主要以DataFrame为主。Panel :三维的数组,可以理解为DataFrame的容器。Pandas官网,更多功能请参考 http://pandas-docs.github.io/…这里我们主要聚焦在Dataframe上,一个dataframe长的基本上如下这番模样:NameAgeMarkJohn1578Mike2386Mary3695我们把这个简单的dataframe起个名字叫df,那么它包括的最基础的元素有:index:每行的索引,默认是从0开始,比如上面的df[0] 就是指 John 15 78这一行,依次类推,当然我们可以自己规定index,我以后会说columns:列。这里就是指的是Name Age Mark 了rows:行,df一共有3行现在让我们看一个完整的图示:Dataframe 是应用最多也是最广泛的数据结构,现在就让我们开始学习创建一个dataframe吧~1.1 创建Dataframe创建一个Dataframe的方法有很多,总体上来说最常见的有及种:创建空dataframe利用dict创建从其他数据源读取(网站,excel,mysql等)真实场景中大多数都是从其他数据源读取,我们会在第3部分讲到创建空dataframe这个非常简单:import pandas as pd # Calling DataFrame constructor df = pd.DataFrame() print(df)Out:Empty DataFrame Columns: [] Index: []利用dict创建(1)import pandas as pdprint (f" Using {pd.name},Version {pd.version}")Out: Using pandas , version 0.23.4首先要import pandas 包,这里缩写为pd,现在让我们从dict创建一个dataframe:>>> dict = {’name’:[“Tom”, “Bob”, “Mary”, “James”], ‘age’: [18, 30, 25, 40], ‘city’:[“Beijing”, “ShangHai”,“GuangZhou”, “ShenZhen”]} >>> df = pd.DataFrame(dict) >>> df创建结果如下: age city name 0 18 Beijing Tom 1 30 ShangHai Bob 2 25 GuangZhou Mary 3 40 ShenZhen James 很简单是不是,大家可能发现了,最左边的东西就是index ,0,1,2,3,如果我们不指定会自动生成从0默认开始的序列,一直到你的dataframe的最后一行,类似于excel左边的编号利用dict创建(2)这次让我们创建的更加规范一些:index = pd.Index([“Tom”, “Bob”, “Mary”, “James”],name = ‘person’)cols = [‘age’,‘city’]data = [[18,‘Beijing’], [30,‘ShangHai’], [25,‘GuangZhou’], [40,‘ShenZhen’]]df =pd.DataFrame(index = index,data =data,columns = cols)df age city person Tom 18 Beijing Bob 30 ShangHai Mary 25 GuangZhou James 40 ShenZhen 这里的主要区别在于我们主动规定了‘name’列为索引。这种把一列默认为索引的方式在excel和sql里都有,异曲同工从其他数据源读取(网站,excel,mysql等)我会在第三部分介绍最常用的从excel,csv等读取数据总体来说,有关创建Dataframe的部分我们不用了解太多,因为实际的场景基本不需要,都是直接从csv,tsv,sql,json等数据源直接获取。2. Dataframe 基础操作这里我们主要看一下基于索引,行,列,行和列的基础操作,最后会为大家总结一下,现在拿刚刚我们创建过的dataframe为例: age city name 0 18 Beijing Tom 1 30 ShangHai Bob 2 25 GuangZhou Mary 3 40 ShenZhen James 2.1 对columns的基础操作添加新列添加一列非常简单:df[‘country’] = ‘USA’df age city name country 0 18 Beijing Tom USA 1 30 ShangHai Bob USA 2 25 GuangZhou Mary USA 3 40 ShenZhen James USA df[‘adress’] = df[‘country’]df age city name country adress 0 18 Beijing Tom USA USA 1 30 ShangHai Bob USA USA 2 25 GuangZhou Mary USA USA 3 40 ShenZhen James USA USA 修改列中的值修改一个列的值也是很容易的,我们可以这样做:df[‘country’] = ‘China’df age city name country adress 0 18 Beijing Tom China USA 1 30 ShangHai Bob China USA 2 25 GuangZhou Mary China USA 3 40 ShenZhen James China USA 或者稍微多想一步:df[‘adress’] = df[‘city’]+’,’+ df[‘country’]df age city name country adress 0 18 Beijing Tom China Beijing,China 1 30 ShangHai Bob China ShangHai,China 2 25 GuangZhou Mary China GuangZhou,China 3 40 ShenZhen James China ShenZhen,China 删除列我们可以应用del或者drop函数,如果是drop,要注意传参时要加上axis = 1.这里简单和大家说明一下axis,这个东西其实就是指轴向,默认的axis=0,是纵向,axis=1是横向df.drop(‘country’,axis=1)df age city name adress 0 18 Beijing Tom Beijing,China 1 30 ShangHai Bob ShangHai,China 2 25 GuangZhou Mary GuangZhou,China 3 40 ShenZhen James ShenZhen,China del df[‘city’]df age name adress 0 18 Tom Beijing,China 1 30 Bob ShangHai,China 2 25 Mary GuangZhou,China 3 40 James ShenZhen,China 这里有一点大家需要注意:drop和del的结果是基于df的两次单独操作,并不是连续的如果我们执行完drop后,重新查看df,这时你会发现df没有变化,因为没有真正的删除要想真正删除,需要加上关键字 inplace = True因此如果我们想要连续删除country和city这两列,改进后的代码如下:df.drop(‘country’,axis=1, inplace=True)del df[‘city’]df age name adress 0 18 Tom Beijing,China 1 30 Bob ShangHai,China 2 25 Mary GuangZhou,China 3 40 James ShenZhen,China 选取列这个非常简单,实现代码如下:df[‘age’] # 选取age这一列 0 18 1 30 2 25 3 40 Name: age, dtype: int64或者这样:df.name 0 Tom 1 Bob 2 Mary 3 James Name: name, dtype: object如果想要选取多个列也很容易,传递一个list就行啦:df[[‘age’,’name’]] age name 0 18 Tom 1 30 Bob 2 25 Mary 3 40 James 这里注意,和选取单独一列不同,这里我们返回的类型是dataframe,之前的类型是series,我们可以这么理解,一列其实还是一维数组,但是两列及以上是二维的了,当然类型也变了如果我们想要查看当前的所有列:df.columnsOut:Index([u’age’, u’name’, u’adress’], dtype=‘object’)如果我们想要重新对列进行命名,基本有三种方法,大家挑一种自己喜欢的就行传递list传递dict传递 axis用list:df.columns = [‘Age’,‘Name’,‘Adress’]df用dict:df.rename(index = str, columns = {‘age’:‘Age’,’name’:‘Name’,‘adress’:‘Adress’}) #这里index=str 有没有都行,我这么做是为了规范df用axis:df.rename(str.capitalize, axis=‘columns’,inplace =True)df最后得到的效果是一样的: Age Name Adress 0 18 Tom Beijing,China 1 30 Bob ShangHai,China 2 25 Mary GuangZhou,China 3 40 James ShenZhen,China 根据条件给列赋值我们现在想要根据人的年龄新增一列 Group,假设要求如下:18岁以下的是年轻人18-30的是中年人30以上的是老年人我们有很多方法可以实现,先看一种,大家可以先忽视loc方法,这里传达的就是基础思路:df[‘Group’] = ’elderly’df.loc[df[‘Age’]<=18, ‘Group’] = ‘young’df.loc[(df[‘Age’] >18) & (df[‘Age’] <= 30), ‘Group’] = ‘middle_aged’df Age Name Adress Group 0 18 Tom Beijing,China young 1 30 Bob ShangHai,China middle_aged 2 25 Mary GuangZhou,China middle_aged 3 40 James ShenZhen,China elderly 2.2 对 rows 的基础操作loc函数 df.loc[row,column]首先,大多数对于行的操作都可以通过loc函数实现,比如我们想要选取全部的行,除了直接打出df外,可以使用df.loc[:]df.loc[:] Age Name Adress Group 0 18 Tom Beijing,China young 1 30 Bob ShangHai,China middle_aged 2 25 Mary GuangZhou,China middle_aged 3 40 James ShenZhen,China elderly loc函数条件查询df.loc[df[‘Age’]>20] Name Age Adress Group 1 Bob 30 ShangHai,China middle_aged 2 Mary 25 GuangZhou,China middle_aged 3 James 40 ShenZhen,China elderly loc函数条件行列查询df.loc[df[‘Group’]==‘middle_aged’,‘Name’]1 Bob2 MaryName: Name, dtype: objectWhere 查询filter_adult = df[‘Age’]>25result = df.where(filter_adult)result Name Age Adress Group 0 NaN NaN NaN NaN 1 Bob 30.0 ShangHai,China middle_aged 2 NaN NaN NaN NaN 3 James 40.0 ShenZhen,China elderly Query 筛选# df.query(‘Age==30’) df.query(‘Group==“middle_aged”‘and ‘Age>30’ ) Name Age Adress Group 3 James 40 ShenZhen,China elderly 2.3 对 Dataframe 的基础了解这里有很多有用的方法,可以帮助到大家大致了解数据的情况:df.shape # 了解行列情况Out:(4, 4)df.describe() # 获取可计算列基础统计 Age count 4.000000 mean 28.250000 std 9.251126 min 18.000000 25% 23.250000 50% 27.500000 75% 32.500000 max 40.000000 # df.head(3) #查看前三行数据,默认为5df.tail(3) #获得最后三行数据 Name Age Adress Group 1 Bob 30 ShangHai,China middle_aged 2 Mary 25 GuangZhou,China middle_aged 3 James 40 ShenZhen,China elderly 3. Pandas读取导出数据(csv)Pandas 支持大部分常见数据文件读取与存储。一般清楚下,读取文件的方法以 pd.read_ 开头,而写入文件的方法以 pd.to_ 开头。这里我们开始熟悉一下最实用的对于csv文件的读取写入写入CSVdf.to_csv(‘person.csv’,index=None,sep=’,’)import osos.getcwd()Out: ‘C:\Users\E560’这样大家就可以在’C:UsersE560’的路径下找到我们刚刚生成的csv文件了,这里我把index=None,舍弃了索引值读取CSV首先我们确认和python文件同一目录下存在我们刚刚导出的person.csv文件,之后可以很容易的读取了:person = pd.read_csv(‘person.csv’)person Name Age Adress Group 0 Tom 18 Beijing,China young 1 Bob 30 ShangHai,China middle_aged 2 Mary 25 GuangZhou,China middle_aged 3 James 40 ShenZhen,China elderly 这时我们发现,即使我们读取的csv文件没有索引,但是pandas已经默认帮我们加上了4. 总结,资料下载好了,现在大家对pandas的使用已经有了基础的印象,我给大家简单总结一下常用的方法:使用标签选取数据df.loc[行标签,列标签]df.loc[‘Tom’:‘Mary’] #选取 Tom至Mary的所有行的数据,Tom和Mary是indexdf.loc[:,‘city’] #选取 city 列的数据df.loc 的第一个参数是行标签,第二个参数为列标签(可选参数,默认为所有列标签),两个参数既可以是列表也可以是单个字符,如果两个参数都为列表则返回的是 DataFrame,否则,则为 Series。PS:loc为location的缩写。使用位置(index)选取数据df.iloc[行位置,列位置] df.iloc[1,1] #选取第二行,第二列的值,返回的为单个值 df.iloc[[0,2],:] #选取第一行及第三行的数据 df.iloc[0:2,:] #选取第一行到第三行(不包含)的数据 df.iloc[:,1] #选取所有记录的第二列的值,返回的为一个Series df.iloc[1,:] #选取第一行数据,返回的为一个SeriesPS:iloc 则为 integer & location 的缩写通过逻辑指针进行数据切片df[逻辑条件]df[df.age >= 18] #单个逻辑条件df[(df.age >=18 ) & (df.country==‘China’) ] #多个逻辑条件组合了解并掌握数据大致情况方法解释count非na值的数量describe针对Series或个DataFrame列计算汇总统计min、max计算最小值和最大值argmin、argmax计算能够获取到最大值和最小值得索引位置(整数)idxmin、idxmax计算能够获取到最大值和最小值得索引值quantile计算样本的分位数(0到1)sum值的总和mean值得平均数median值得算术中位数(50%分位数)mad根据平均值计算平均绝对离差var样本值的方差std样本值的标准差skew样本值得偏度(三阶矩)kurt样本值得峰度(四阶矩)cumsum样本值得累计和cummin,cummax样本值得累计最大值和累计最小值cumprod样本值得累计积diff计算一阶差分(对时间序列很有用)pct_change计算百分数变化常见读取写入数据数据类型读取写入CSVread_csvto_csvJSONread_jsonto_jsonHTMLread_htmlto_htmlEXCELread_excelto_excelSQLread_sqlto_sql好了,其实这些就是想要告诉大家如何学习pandas,没有必要了解每一个方法,但是现在想必你知道pandas能实现的功能很多,这样你有具体需求时只要详细查询一下文档即可,接下来几期我们会重点来看pandas里面对于df的各种操作,从简单的数据清理到类似于excel里面的vba,包括cancat,merge,join等等下载我把这一期的ipynb文件和py文件放到了GIthub上,大家如果想要下载可以点击下面的链接:Github仓库地址: 点我下载好啦,这一期就讲这么多,希望大家能够继续支持我,完结,撒花 ...

March 4, 2019 · 4 min · jiezi

github 授权登录教程与如何设计第三方授权登录的用户表

需求:在网站上想评论一篇文章,而评论文章是要用户注册与登录的,那么怎么免去这麻烦的步骤呢?答案是通过第三方授权登录。本文讲解的就是 github 授权登录的教程。效果体验地址: http://biaochenxuying.cn1. github 第三方授权登录教程先来看下 github 授权的完整流程图 1:或者看下 github 授权的完整流程图 2:1.1 申请一个 OAuth App首先我们必须登录上 github 申请一个 OAuth App,步骤如下:登录 github点击头像下的 Settings -> Developer settings 右侧 New OAuth App填写申请 app 的相关配置,重点配置项有2个Homepage URL 这是后续需要使用授权的 URL ,你可以理解为就是你的项目根目录地址Authorization callback URL 授权成功后的回调地址,这个至关重要,这是拿到授权 code 时给你的回调地址。具体实践如下:首先登录你的 GitHub 账号,然后点击进入Settings。点击 OAuth Apps , Register a new application 或者 New OAuth App 。输入信息。应用信息说明。流程也可看 GitHub 设置的官方文档-Registering OAuth Apps。1.2 授权登录github 文档:building-oauth-apps/authorizing-oauth-apps授权登录的主要 3 个步骤:web 端重定向 http://github.com/login/oauth…根据 code 获取 access_token根据 access_token 获取用户信息笔者这次实践中,项目是采用前后端分离的,所以第 1 步在前端实现,而第 2 步和第 3 步是在后端实现的,因为第 2 个接口里面需要Client_secret 这个参数,而且第 3 步获取的用户信息在后端保存到数据库。1.3. 代码实现1.3.1 前端笔者项目的技术是 react。// config.js// ***** 处请填写你申请的 OAuth App 的真实内容 const config = { ‘oauth_uri’: ‘https://github.com/login/oauth/authorize', ‘redirect_uri’: ‘http://biaochenxuying.cn/', ‘client_id’: ‘’, ‘client_secret’: ‘*’,};// 本地开发环境下if (process.env.NODE_ENV === ‘development’) { config.redirect_uri = “http://localhost:3001/” config.client_id = “” config.client_secret = “"}export default config; 代码参考 config.js redirect_uri 回调地址是分环境的,所以我是新建了两个 OAuth App 的,一个用于线上生产环境,一个用于本地开发环境。一般来说,登录的页面应该是独立的,对应相应的路由 /login , 但是本项目的登录 login 组件是 nav 组件的子组件,nav 是个全局用的组件, 所以回调地址就写了 http://biaochenxuying.cn/。所以点击跳转是写在 login.js 里面;授权完拿到 code 后,是写在 nav.js 里面nav.js 拿到 code 值后去请求后端接口,后端接口返回用户信息。其中后端拿到 code 还要去 github 取 access_token ,再根据 access_token 去取 github 取用户的信息。// login.js// html<Button style={{ width: ‘100%’ }} onClick={this.handleOAuth} > github 授权登录</Button>// jshandleOAuth(){ // 保存授权前的页面链接 window.localStorage.preventHref = window.location.href // window.location.href = ‘https://github.com/login/oauth/authorize?client_id=&redirect_uri=http://biaochenxuying.cn/’ window.location.href = ${config.oauth_uri}?client_id=${config.client_id}&amp;redirect_uri=${config.redirect_uri}}代码参考 login.js // nav.jscomponentDidMount() { // console.log(‘code :’, getQueryStringByName(‘code’)); const code = getQueryStringByName(‘code’) if (code) { this.setState( { code }, () => { if (!this.state.code) { return; } this.getUser(this.state.code); }, ); } }componentWillReceiveProps(nextProps) { const code = getQueryStringByName(‘code’) if (code) { this.setState( { code }, () => { if (!this.state.code) { return; } this.getUser(this.state.code); }, ); } } getUser(code) { https .post( urls.getUser, { code, }, { withCredentials: true }, ) .then(res => { // console.log(‘res :’, res.data); if (res.status === 200 && res.data.code === 0) { this.props.loginSuccess(res.data); let userInfo = { _id: res.data.data._id, name: res.data.data.name, }; window.sessionStorage.userInfo = JSON.stringify(userInfo); message.success(res.data.message, 1); this.handleLoginCancel(); // 跳转到之前授权前的页面 const href = window.localStorage.preventHref if(href){ window.location.href = href } } else { this.props.loginFailure(res.data.message); message.error(res.data.message, 1); } }) .catch(err => { console.log(err); }); }参考 nav.js 1.3.2 后端笔者项目的后端采用的技术是 node.js 和 express。后端拿到前端传来的 code 后,还要去 github 取 access_token ,再根据 access_token 去取 github 取用户的信息。然后把要用到的用户信息通过 注册 的方式保存到数据库,然后返回用户信息给前端。// app.config.jsexports.GITHUB = { oauth_uri: ‘https://github.com/login/oauth/authorize', access_token_url: ‘https://github.com/login/oauth/access_token', // 获取 github 用户信息 url // eg: https://api.github.com/user?access_token=&scope=&token_type=bearer user_url: ‘https://api.github.com/user', // 生产环境 redirect_uri: ‘http://biaochenxuying.cn/', client_id: ‘’, client_secret: ‘’, // // 开发环境 // redirect_uri: “http://localhost:3001/”, // client_id: “”, // client_secret: “***”,};代码参考 app.config.js // 路由文件 user.jsconst fetch = require(’node-fetch’);const CONFIG = require(’../app.config.js’);const User = require(’../models/user’);// 第三方授权登录的用户信息exports.getUser = (req, res) => { let { code } = req.body; if (!code) { responseClient(res, 400, 2, ‘code 缺失’); return; } let path = CONFIG.GITHUB.access_token_url; const params = { client_id: CONFIG.GITHUB.client_id, client_secret: CONFIG.GITHUB.client_secret, code: code, }; // console.log(code); fetch(path, { method: ‘POST’, headers: { ‘Content-Type’: ‘application/json’, }, body: JSON.stringify(params), }) .then(res1 => { return res1.text(); }) .then(body => { const args = body.split(’&’); let arg = args[0].split(’=’); const access_token = arg[1]; // console.log(“body:",body); console.log(‘access_token:’, access_token); return access_token; }) .then(async token => { const url = CONFIG.GITHUB.user_url + ‘?access_token=’ + token; console.log(‘url:’, url); await fetch(url) .then(res2 => { console.log(‘res2 :’, res2); return res2.json(); }) .then(response => { console.log(‘response ‘, response); if (response.id) { //验证用户是否已经在数据库中 User.findOne({ github_id: response.id }) .then(userInfo => { // console.log(‘userInfo :’, userInfo); if (userInfo) { //登录成功后设置session req.session.userInfo = userInfo; responseClient(res, 200, 0, ‘授权登录成功’, userInfo); } else { let obj = { github_id: response.id, email: response.email, password: response.login, type: 2, avatar: response.avatar_url, name: response.login, location: response.location, }; //注册到数据库 let user = new User(obj); user.save().then(data => { // console.log(‘data :’, data); req.session.userInfo = data; responseClient(res, 200, 0, ‘授权登录成功’, data); }); } }) .catch(err => { responseClient(res); return; }); } else { responseClient(res, 400, 1, ‘授权登录失败’, response); } }); }) .catch(e => { console.log(’e:’, e); });};代码参考 user.js 至于拿到 github 的用户信息后,是注册到 user 表,还是保存到另外一张 oauth 映射表,这个得看自己项目的情况。从 github 拿到的用户信息如下图:最终效果:参与文章:https://www.jianshu.com/p/a9c…https://blog.csdn.net/zhuming...2. 如何设计第三方授权登录的用户表第三方授权登录的时候,第三方的用户信息是存数据库原有的 user 表还是新建一张表呢 ?答案:这得看具体项目了,做法多种,请看下文。第三方授权登录之后,第三方用户信息一般都会返回用户唯一的标志 openid 或者 unionid 或者 id,具体是什么得看第三方,比如 github 的是 id1. 直接通过 注册 的方式保存到数据库第一种:如果网站 没有 注册功能的,直接通过第三方授权登录,授权成功之后,可以直接把第三的用户信息 注册 保存到自己数据库的 user 表里面。典型的例子就是 微信公众号的授权登录。第二种:如果网站 有 注册功能的,也可以通过第三方授权登录,授权成功之后,也可以直接把第三的用户信息 注册 保存到自己数据库的 user 表里面(但是密码是后端自动生成的,用户也不知道,只能用第三方授权登录),这样子的第三方的用户和原生注册的用户信息都在同一张表了,这种情况得看自己项目的具体情况。笔者的博客网站暂时就采用了这种方式。2. 增加映射表现实中很多网站都有多种账户登录方式,比如可以用网站的注册 id 登录,还可以用手机号登录,可以用 QQ 登录等等。数据库中都是有映射关系,QQ、手机号等都是映射在网站的注册 id 上。保证不管用什么方式登录,只要去查映射关系,发现是映射在网站注册的哪个 id 上,就让哪个 id 登录成功。3. 建立一个 oauth 表,一个 id 列,记录对应的用户注册表的 id建立一个 oauth 表,一个 id 列,记录对应的用户注册表的 id,然后你有多少个第三方登陆功能,你就建立多少列,记录第三方登陆接口返回的 openid;第三方登陆的时候,通过这个表的记录的 openid 获取 id 信息,如果存在通过 id 读取注册表然后用 session 记录相关信息。不存在就转向用户登陆/注册界面要用户输入本站注册的账户进行 openid 绑定或者新注册账户信息进行绑定。具体代码实践请参考文章:1. 第三方登录用户信息表设计2. 浅谈数据库用户表结构设计,第三方登录4. 最后笔者的 github 博客地址:https://github.com/biaochenxuying/blog如果您觉得这篇文章不错或者对你有所帮助,请给个赞或者星呗,你的点赞就是我继续创作的最大动力。微信公众号:BiaoChenXuYing分享 前端、后端开发等相关的技术文章,热点资源,随想随感,全栈程序员的成长之路。关注公众号并回复 福利 便免费送你视频资源,绝对干货。福利详情请点击: 免费资源获取–Python、Java、Linux、Go、node、vue、react、javaScript ...

March 4, 2019 · 4 min · jiezi

ubuntu18.04下VSCode通过ssh连接github实操

前言一般来说,我们从github克隆代码,有两个模式,一个是https模式,一个是ssh模式。如果我么没有建立ssh信任,是无法通过ssh模式克隆代码的。ssh模式有一个优势就是可以建立本地git工具和github服务器之间的信任,不需要使用账号密码登录,尤其是我们push origin提交服务器的时候,省去输入账号密码的步骤。场景系统:ubuntu 18.04工具:VSCode 1.31.1工具:git 2.17.1过程本地准备SSH-KEY打开终端,cd ~进入根目录,执行ssh keygen,一路回车,生成本地的SSH-KEY,在目录/home/myubuntu/.ssh下分别是id_rsa和id_rsa.pub文件。其中id_rsa.pub文件是公钥,另一个id_rsa是私钥。公约提供给服务器,私钥自己保留,在这里,服务器就是github。把SSH-KEY写入服务器登录github,访问https://github.com/settings/keys页面,主页面有两个模块SSH keys和GPG keys,我们需要使用的是SSH keys。右边页面有一个绿色按钮New SSH key,点击会出现添加栏,分别是Title和Key。把本地文件id_rsa.pub打开,可以在/home/myubuntu/.ssh下执行命令vi id_rsa.pub,完整复制粘贴到Key输入栏,Title可以随便命名,比如ubuntu key,点击下方的绿色按钮Add SSH key,保存成功。在本地终端执行命令ssh -T git@github.com,会用本地秘钥连接github主机,如果有提示You’ve successfully authenticated, but GitHub does not provide shell access.代表连接成功。这时候可以通过ssh从自己的github仓库拉取项目了。拉取数据的时候必须选择ssh地址,复制到本地终端,进入存放代码的目录,执行命令git clone git@github.com:No2015/vue-cli3-typescript.git。只有通过ssh拉取的项目才能通过ssh来控制。本地项目克隆完毕,安装依赖模块,正常运行之后。如果修改成功,可以通过命令行执行git add .、git commit -m ‘add all’,git push origin master三个命令提交代码。或者通过VSCode工具提供的快捷方式提交。因为有ssh签名的信任,账号密码都是免除了的,省事很多。结语之前搞了一小会儿,因为项目是通过https模式拉取下来的,ssh建立之后还是需要输入账号密码,折腾很长时间才发现,修改本地仓库的remote就好了,或者删除本地代码,重新通过ssh拉取新代码。修改本地仓库地址的命令是git remote set-url origin git@github.com:No2015/vue-cli3-typescript.git

March 1, 2019 · 1 min · jiezi

如何制作可以在 MaxCompute 上使用的 crcmod

之前我们介绍过在 PyODPS DataFrame 中使用三方包。对于二进制包而言,MaxCompute 要求使用包名包含 cp27-cp27m 的 Wheel 包。但对于部分长时间未更新的包,例如 oss2 依赖的 crcmod,PyPI 并未提供 Wheel 包,因而需要自行打包。本文介绍了如何使用 quay.io/pypa/manylinux1_x86_64 镜像制作可在 MaxCompute 上使用的 Wheel 包。本文参考 https://github.com/pypa/manylinux ,quay.io/pypa/manylinux1_x86_64 镜像也是目前绝大多数 Python 项目在 Travis CI 上打包的标准工具,如有进一步的问题可研究该项目。1. 准备依赖项不少包都有依赖项,例如 devel rpm 包或者其他 Python 包,在打包前需要了解该包的依赖,通常可以在 Github 中找到安装或者打包的相关信息。对于 crcmod,除 gcc 外不再有别的依赖,因而此步可略去。2. 修改 setup.py 并验证(建议在 Mac OS 或者 Linux 下)较旧的 Python 包通常不支持制作 Wheel 包。具体表现为在使用 python setup.py bdist_wheel 打包时报错。如果需要制作 Wheel 包,需要修改 setup.py 以支持 Wheel 包的制作。对于一部分包,可以简单地将 distutils 中的 setup 函数替换为 setuptools 中的 setup 函数。而对于部分自定义操作较多的 setup.py,需要详细分析打包过程,这一项工作可能会很复杂,本文就不讨论了。例如,对于 crcmod,修改 setup.py 中的from distutils.core import setup为from setuptools import setup即可。修改完成后,在项目根目录执行python setup.py bdist_wheel如果没有报错且生成的 Wheel 包可在本地使用,说明 setup.py 已可以使用。3. 准备打包脚本在项目中新建 bin 目录,并在其中创建 build-wheel.sh:mkdir bin && vim bin/build-wheel.sh在其中填入以下内容:#!/bin/bash# modified from https://github.com/pypa/python-manylinux-demo/blob/master/travis/build-wheels.shset -e -x# Install a system package required by our library# 将这里修改为安装依赖项的命令# Compile wheelsPYBIN=/opt/python/cp27-cp27m/bin# 如果包根目录下有 dev-requirements.txt,取消下面的注释# “${PYBIN}/pip” install -r /io/dev-requirements.txt"${PYBIN}/pip" wheel /io/ -w wheelhouse/# Bundle external shared libraries into the wheelsfor whl in wheelhouse/*.whl; do auditwheel repair “$whl” -w /io/wheelhouse/done将第一步获知的依赖项安装脚本填入此脚本,在使用 python 或 pip 时,注意使用 /opt/python/cp27-cp27m/bin 中的版本。最后,设置执行权限chmod a+x bin/build-wheel.sh4. 打包使用 Docker 下载所需的镜像(本步需要使用 Docker,请提前安装),此后在项目根目录下打包:docker pull quay.io/pypa/manylinux1_x86_64docker run –rm -v pwd:/io quay.io/pypa/manylinux1_x86_64 /io/bin/build-wheel.sh完成的 Wheel 包位于项目根目录下的 wheelhouse 目录下。本文作者:继盛阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

March 1, 2019 · 1 min · jiezi

Mac 鼠须管 Rime 输入法 安装五笔输入法 教程

Mac 鼠须管 Rime 输入法 安装五笔输入法 教程相关链接极点五笔方案(github): https://github.com/KyleBing/r...RIME 官网: https://rime.im/RIME github 地址: https://github.com/rimeRIME 输入方案集合: https://github.com/rime/plumRIME 官方五笔码表: https://github.com/rime/rime-...RIME 简拼输入方案: https://github.com/rime/rime-…前言Rime 是一款跨平台的优秀输入法的内核。该输入法在不同平台的名字也不同Windows - 小狼毫macOS - 鼠须管Linux - ibus-rimeRime 输入法的优势在于它高度的可自定义化,不单单可以定义输入法码表,还可以定义输入法翻译码表的方式,标点对应等等等等。高度自定义的特性也使得入门的门槛比较高一些。如果想自定义方案,需要有一定的编程基础,至少有一定的程序语言基础。用极点输入法的原因用久了五笔的都知道,喜欢五笔的因为是五笔的重码率少,如果码表太多重码就体验很差了。这里导入的极点版是重码很少的,打起字来很爽的。而且对标点的支持也很好。之前用的 清歌输入法,但该输入法有个弊端,对于我这种前端工程师来说,会在工作中用到数字左边那个键 ~,而清歌输入法把这个键作为临时拼音输入的入口,用起来就各种麻烦。现在换成 RIME 简直爽翻了。 好久没有这么爽的打过字了。管去 官网下载,或者直接点这里下载文章发布时的 鼠须管 最新版 0.11官网下载 (https://rime.im/download/)鼠须管 最新版 0.11 (https://dl.bintray.com/rime/s…下载后按照步骤安装即可下载 五笔配置文件为了方便朋友们下载,我新建了一个 github 配置文件仓库,可以直接下载五笔输入法-极点版: https://github.com/KyleBing/r…其中的文件列表有:.├── README.md # 当前说明文档├── default.custom.yaml # 用记自定义的一些输入方式或方向├── pinyin_simp.dict.yaml # 简体拼音码表 - 五笔中拼音输入需要的├── pinyin_simp.schema.yaml # 简体拼音解释器├── squirrel.custom.yaml # 输入法候选词界面├── wubi86.dict.yaml # 官方五笔码表├── wubi86.schema.yaml # 五笔解释器├── wubi86_jidian.dict.yaml # 极点 - 五笔码表├── wubi86_jidian.schema.yaml # 极点 - 五笔码表解释器├── wubi_pinyin.schema.yaml # 五笔拼音混输└── wubi_trad.schema.yaml # 五笔简入繁出目前的功能特点control + 1 呼出设置菜单(在有些应用中可能会失效,换个应用就好)显示 3 个候选词分号; 和 引号‘ 作为二三候选的快捷键4 码唯一时直接上屏设置五笔输入法Rime 输入法的设置方式:把配置文件放到配置目录,在状态栏的输入法中选择 鼠须管,执行一下 部署 就好了。macOS 上的 刀须管 设置目录是 ~/Library/Rime把上面下载的文件移到该目录中,点击 部署 即可。关于自定义一些功能< 这个等有时间再写吧 > ...

February 28, 2019 · 1 min · jiezi

git 本地仓库与远程仓库的强制合并 refusing to merge unrelated histories

git 本地仓库与远程仓库的强制合并错误提示: refusing to merge unrelated historiesThe local repository is out of date过程是这样的今天在本地新建了一个 git 仓库,并往里添加了一些文件,也在本地提交了几次。这时候再去 github 上新建了个仓库,然后把 github仓库添加到本地的仓库中。git remote add rime git@github.com:KyleBing/rime-wubi86-jidan.git可以看到已经添加了远程仓库:pull 远程仓库的内容:然后执行上传到 github 的时候出现下面错误:错误原因其实本地建的那个仓库和远程 github 仓库是两个独立的仓库,互不相关。如果在建完 github 后再 git clone 到本地就不会出现该问题了。解决办法git pull 有个 –allow-unrelated-histories 参数,是为了合并两个不相关的仓库的历史,这个可以通过 git pull –h 查看帮助。因为我们这两个仓库并没有冲突,可以直接合并:git pull rime master –allow-unrelated-histories这时候出现填写合并信息的窗口填写保存后,结果显示,合并成功。后续提交# 提交更新到 githubkyle-mbp:Rime Kyle$ git push rime master# 结果Counting objects: 38, done.Delta compression using up to 4 threads.Compressing objects: 100% (38/38), done.Writing objects: 100% (38/38), 1.85 MiB | 305.00 KiB/s, done.Total 38 (delta 20), reused 0 (delta 0)remote: Resolving deltas: 100% (20/20), done.To github.com:KyleBing/rime-wubi86-jidan.git 27c22af..bf39b8c master -> master查看历史记录是这样的,可以看到本地 master 和远程 master 已经合并在一起了:再看一下远程仓库的提交记录,已经能看到本地的提交记录了。结决 ...

February 28, 2019 · 1 min · jiezi

Spring Data JPA 必须掌握的 20+ 个查询关键字

微信公众号:一个优秀的废人如有问题或建议,请后台留言,我会尽力解决你的问题。前言又是小师弟的投稿,确是一个喜欢技术的朋友。以下为原文:今天闲的无聊看 Spring Data JPA 官方文档的时候,发现并没有完整的 Jpa 关键字语义翻译。所以今天写了一篇中文文档,如果有错误,望大家轻喷。以下为官方图片以及示例代码和注释 :首先参照官方文档创建指定数据库CREATE TABLE demo_jpa ( id int(11) NOT NULL AUTO_INCREMENT, first_name varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, last_name varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, sex varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, email varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, age int(12) NOT NULL, PRIMARY KEY (id) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;示例代码及注释<参照以上顺序>/** * @Author: EvilSay * @Date: 2019/2/25 16:15 /public interface DemoJpaRepositories extends JpaRepository<DemoJpa,Integer> { //根据firstName与LastName查找(两者必须在数据库有) DemoJpa findByFirstNameAndLastName(String firstName, String lastName); //根据firstName或LastName查找(两者其一有就行) DemoJpa findByLastNameOrFirstName(String lastName,String firstName); //根据firstName查找它是否存在数据库里<类似与以下关键字> //DemoJpa findByFirstName(String firstName); DemoJpa findByFirstNameIs(String firstName); //在Age数值age到age2之间的数据 List<DemoJpa> findByAgeBetween(Integer age, Integer age2); //小于指定age数值之间的数据 List<DemoJpa> findByAgeLessThan(Integer age); //小于等于指定age数值的数据 List<DemoJpa> findByAgeLessThanEqual(Integer age); //大于指定age数值之间的数据 List<DemoJpa> findByAgeGreaterThan(Integer age); //大于或等于指定age数值之间的数据 List<DemoJpa> findByAgeGreaterThanEqual(Integer age); //在指定age数值之前的数据类似关键字<LessThan> List<DemoJpa> findByAgeAfter(Integer age); //在指定age数值之后的数据类似关键字<GreaterThan> List<DemoJpa> findByAgeBefore(Integer age); //返回age字段为空的数据 List<DemoJpa> findByAgeIsNull(); //返回age字段不为空的数据 List<DemoJpa> findByAgeNotNull(); /* * 该关键字我一度以为是类似数据库的模糊查询, * 但是我去官方文档看到它里面并没有通配符。 * 所以我觉得它类似 * DemoJpa findByFirstName(String firstName); * @see https://docs.spring.io/spring-data/jpa/docs/2.1.5.RELEASE/reference/html/#jpa.repositories */ DemoJpa findByFirstNameLike(String firstName); //同上 List<DemoJpa> findByFirstNameNotLike(String firstName); //查找数据库中指定类似的名字(如:输入一个名字"M" Jpa会返回多个包含M开头的名字的数据源)<类似数据库模糊查询> List<DemoJpa> findByFirstNameStartingWith(String firstName); //查找数据库中指定不类似的名字(同上) List<DemoJpa> findByFirstNameEndingWith(String firstName); //查找包含的指定数据源(这个与以上两个字段不同的地方在与它必须输入完整的数据才可以查询) List<DemoJpa> findByFirstNameContaining(String firstName); //根据age选取所有的数据源并按照LastName进行升序排序 List<DemoJpa> findByAgeOrderByLastName(Integer age); //返回不是指定age的所有数据 List<DemoJpa> findByAgeNot(Integer age); //查找包含多个指定age返回的数据 List<DemoJpa> findByAgeIn(List<Integer> age);}单元测试<已经全部通过>@SpringBootTest@RunWith(SpringRunner.class)@Slf4jpublic class DemoJpaRepositoriesTest { @Autowired private DemoJpaRepositories repositories; @Test public void findByFirstNameAndLastName() { DemoJpa demoJpa = repositories.findByFirstNameAndLastName(“May”, “Eden”); Assert.assertEquals(demoJpa.getFirstName(),“May”); } @Test public void findByLastNameOrFirstName() { DemoJpa demoJpa = repositories.findByLastNameOrFirstName(“Geordie”, “Eden”); Assert.assertNotEquals(demoJpa.getLastName(),“Eden”); } @Test public void findByFirstNameIs() { DemoJpa demoJpa = repositories.findByFirstNameIs(“amy”); Assert.assertNull(demoJpa); } @Test public void findByAgeBetween() { List<DemoJpa> demoJpaList = repositories.findByAgeBetween(15, 17); Assert.assertEquals(3,demoJpaList.size()); } @Test public void findByAgeLessThan() { List<DemoJpa> demoJpaList = repositories.findByAgeLessThan(17); Assert.assertEquals(2,demoJpaList.size()); } @Test public void findByAgeLessThanEqual() { List<DemoJpa> demoJpaList = repositories.findByAgeLessThanEqual(17); Assert.assertEquals(3,demoJpaList.size()); } @Test public void findByAgeGreaterThan() { List<DemoJpa> demoJpaList = repositories.findByAgeGreaterThan(17); Assert.assertEquals(2,demoJpaList.size()); } @Test public void findByAgeGreaterThanEqual() { List<DemoJpa> demoJpaList = repositories.findByAgeGreaterThanEqual(17); Assert.assertEquals(3,demoJpaList.size()); } @Test public void findByAgeAfter() { List<DemoJpa> demoJpaList = repositories.findByAgeAfter(17); Assert.assertEquals(2,demoJpaList.size()); } @Test public void findByAgeBefore() { List<DemoJpa> demoJpaList = repositories.findByAgeBefore(17); Assert.assertEquals(2,demoJpaList.size()); } @Test public void findByAgeIsNull() { List<DemoJpa> demoJpaList = repositories.findByAgeIsNull(); Assert.assertEquals(0,demoJpaList.size()); } @Test public void findByAgeNotNull() { List<DemoJpa> demoJpaList = repositories.findByAgeNotNull(); Assert.assertEquals(5,demoJpaList.size()); } @Test public void findByFirstNameLike() { DemoJpa demoJpa = repositories.findByFirstNameLike(“May”); Assert.assertNotNull(demoJpa); } @Test public void findByFirstNameNotLike() { } @Test public void findByFirstNameStartingWith() { List<DemoJpa> demoJpaList = repositories.findByFirstNameStartingWith(“May”); Assert.assertEquals(2,demoJpaList.size()); } @Test public void findByFirstNameEndingWith() { List<DemoJpa> demoJpaList = repositories.findByFirstNameEndingWith(“Evil”); Assert.assertEquals(0,demoJpaList.size()); } @Test public void findByFirstNameContaining() { List<DemoJpa> demoJpaList = repositories.findByFirstNameContaining(“hack”); Assert.assertEquals(0,demoJpaList.size()); } @Test public void findByAgeOrderByLastName() { List<DemoJpa> demoJpaList = repositories.findByAgeOrderByLastName(18); for (DemoJpa demoJpaL : demoJpaList){ log.info(“数据结果”+demoJpaL.toString()); } } @Test public void findByAgeNot() { List<DemoJpa> demoJpaList = repositories.findByAgeNot(20); Assert.assertEquals(5,demoJpaList.size()); } @Test public void findByAgeIn() { List<DemoJpa> demoJpaList = repositories.findByAgeIn(Arrays.asList(15, 16)); Assert.assertEquals(2,demoJpaList.size()); }}后语如果本文对你哪怕有一丁点帮助,请帮忙点好看。你的好看是我坚持写作的动力。另外,关注之后在发送 1024 可领取免费学习资料。资料内容详情请看这篇旧文:Python、C++、Java、Linux、Go、前端、算法资料分享 ...

February 27, 2019 · 2 min · jiezi

ZIlliqa团队关于分片、可扩展性和安全的智能合约的采访

Zilliqa是一个用来托管去中心化应用的安全且可扩展的区块链平台,与其他DAPP平台相比,它具有一些突出的功能。首先,它使用分片来确保极高的吞吐量,能比当前大多数平台每秒多处理大约200个交易。其次,团队开发了用于Zilliqa平台的自己的智能合约编程语言Scilla。他们把Scilla设计的比现有智能合约编程语言更安全,例如Solidity,其经常会出现一些漏洞使得智能合约容易被攻击。Zilliqa团队将于今年第一季度发布其主网。我们有机会与首席执行官兼联合创始人董心书(XD)和首席营销官Yiling Ding(YD)坐下来,了解所有最新消息和发展情况。Xinshu Dong, CEO, and Yiling Ding, CMO01、区块链开发人员一直在努力解决可扩展性问题,您如何看待可扩展性影响了区块链游戏的可持续性?游戏如何促进应对可扩展性挑战?YD:在游戏产业中,区块链可扩展性的限制会明显地立即呈现给开发者和用户。一个衡量游戏是否成功的可靠方法就是它的受欢迎程度。如今的区块链平台已经在为每天容纳1000名活跃用户(DAU)而努力,但随着游戏越来越成功,用户群持续增长,现实是它们几乎不可能继续运行在区块链上。虽然可以将游戏的大部分交易转移到链下,但这样做只会违背区块链游戏的初衷。这些扩展性难题不可避免地导致糟糕的用户体验(UX),因为它们阻碍了持续的游戏体验——网络难以及时完成交易,用户被迫为每笔交易等待几分钟。虽然技术创新和进步通常是值得庆祝的,与交易最终性相关的问题通常不会出现在数字游戏中。这种糟糕的体验将阻碍未来的游戏玩家和游戏开发商进入区块链游戏。考虑到这一点,游戏行业正在给区块链平台带来实际和具体的挑战来处理,并有可能在将来克服这些挑战。通过开发专门针对类似游戏内市场交易等问题的扩展解决方案,项目将能够超越“为了可扩展性而扩展”的思路,从而开发用来展示区块链如何增强现有项目、平台和应用程序的解决方案。02、您对不可替代资产如何影响游戏有何看法?对于普通玩家来说,这意味着什么,特别是当我们听说孩子们破解类似Fortnite这样的游戏,并在网上卖帐号时?YD:不可替代资产有两个主要好处:游戏资产交换的安全性提高,以及拥有真正保存和保护它们的能力。长期以来,游戏界一直在寻求将游戏内资产变现的方法,从而建立了非官方的黑市,用户在那里交易物品,无论是皮肤还是像Fortnite这样的大型角色扮演游戏中拥有高级角色的账户。这些非官方渠道对购买资产的玩家具有很高的风险,因为他们容易遭受欺诈和信息盗窃。代币化的替代方案为买方和卖方提供了额外的安全保护——卖方需要证明其对所交换物品的所有权,并且因为交易发生在一个去中心化平台上,不需要共享个人身份信息。这些代币还具有真正的永久性和所有权,因此玩家可以确信他们的资产是真正属于自己的,并保持可交易性。相比之下,如果将平台托管在一个中心化的服务器上,开发人员可以轻松关闭或更改其市场,从而导致游戏玩家失去资产。03、Zilliqa使用分片和pow/pbft组合协议来实现交易处理速度的可扩展性,每秒可处理高达3000个交易。您能和我们详细谈一下你们的共识协议以及它是如何工作的吗?XD:我们的共识协议由四部分组成,它使用了POW和PBFT,以便在保障高安全性的同时支持更高的交易吞吐量。第一个阶段包括一个五分钟的时间窗口,用来让所有挖矿节点提交他们的POW工作量证明——POW仅限于此阶段,让矿工建立他们的身份,并防止女巫攻击。之后,满足一定全局难度要求的挖矿节点的第一子集可以作为目录服务节点(Directory Service Nodes)或分片节点(Shard Nodes)加入。一旦分片建立起来,这些小组就会进行多轮PBFT共识,签署新的区块(或交易块)并提交给网络。然后,签署了区块的所有节点将公平地分配区块奖励。在一轮POW中,可以将多个区块写入链中,从而并行处理多个交易。04、可扩展性通常可以与恢复能力很好地保持平衡。您能解释一下Zilliqa是如何在维护网络安全的同时实现高吞吐量的吗?XD:安全性对我们来说是一个关键的优先事项,当涉及到我们的共识协议和编程语言Scilla的创建时,它推动了我们的大量决策。它也是我们在研究可扩展解决方案时考虑的一个关键因素。因此,虽然提出了许多区块链扩展的解决方案,我们发现分片是一种可行的链上解决方案,可以让我们保持去中心化、可扩展性和安全性。通过选择链上扩展,由于区块链以其自身提供的全面安全保证运行,因此可以安全地进行分片。去中心化在维护安全方面也发挥了很大作用,公共选择节点的共识和交易的第三方抗审查对于区块链的安全至关重要。Transactions per second05、您能解释一下为什么您决定开发独立的智能合约编程语言Scilla,而不是采用其他编程语言,如JavaScript或Solidity吗?Scilla和那些语言有什么不同?XD:在设计智能合约时,相较于智能合约的其他方面我们特意决定优先考虑智能合约的安全,因为我们认为安全对于推动智能合约技术被主流采用至关重要。尽管我们可以选择使用已经存在的编程语言,如solidity和javascript,但我们的技术评估发现,根据它们的现有句法和语法,想依靠它们是非常困难的。Scilla与Solidity和JavaScript的主要区别在于高安全性和易用性——这些是其底层设计原则。Scilla能够形式化(数学上)验证智能合约的安全性和正确性,消除了语言级别的几个常见安全漏洞,例如对智能合约的可重入调用和整数上/下溢出。06、Zilliqa的用例主要是游戏、数字广告和支付。为什么是这三类特定的用例?使用Zilliqa作为其他类型的DAPP(比如交易所)的平台是否有限制?YD:Zilliqa是一个开放的公共平台,所以对在我们的区块链上搭建什么内容没有限制。我们目前的合作对象之一Bolt Global,是一个基于区块链的移动娱乐系统,就不属于这三个类别。也就是说,游戏、数字广告和支付是我们认为急需高吞吐量区块链解决方案的行业,因此它们是我们目前在合作、研究和开发方面的重点领域。在游戏中,我们已经看到可扩展性已经成为区块链游戏的一个明显瓶颈。例如,由于以太坊太拥堵,交易费用太高,影响了整个游戏体验,所以以太小怪兽游戏(Etheremon)不得不将它们的大部分游戏移到链下。在数字广告中,区块链有助于解决广告欺诈和广告曝光量等问题,这将使媒体公司、广告商和消费者受益。除此之外,也需要一个高吞吐量的平台来支持每天在广告交易平台上发生的大量广告活动。支付也是一个明显的用例,因为它们需要高安全性和高吞吐量来处理大量的交易。除此之外,证券代币和证券代币发行等金融工具也将受益于Zilliqa可以提供的一个强大、安全的发行平台。07、Zilliqa最近在Coinbase Pro上市,这是一项伟大的成就,可以有助于提升项目的价值。你对Vitalik Buterin关于中心化交易所应该“在地狱里燃烧”的有争议的说法怎么看?去中心化应该成为所有区块链项目的目标,还是您认为在中长期的未来,中心化机构仍可以扮演某些角色?XD:支持企业和用户的去中心化应用程序是我们的一个关键目标,实际上也是我们的推动力。同时,我们也认识到在性能和延迟方面,中心化平台为完全去中心化的系统提供了互补的好处。同样不要忘记,区块链的安全性和弹性都以某种方式依赖于其内置的冗余——这会影响性能,但这是区块链固有分布式特性的结果。08、作为其本土,Zilliqa在亚洲获得了很多认可,但其在欧洲也有扩张计划––据我们了解,你们几个月前在伦敦开设了一家办事处。除此之外,还有其它什么在亚洲之外的扩张计划?YD:我们向欧洲扩张有很多原因,但一个主要的驱动力是蓬勃发展的开发者社区。整个欧洲大陆都遍布着开发人员的温床,如爱沙尼亚、保加利亚和罗马尼亚,我们最近在那里举办了一次开发人员研讨会。我们将继续与整个欧洲的开发者社区进行合作,还有一些我们感兴趣的特定地区。例如,法国以其功能性程序员而闻名,这为我们利用这些人才来提高知名度和鼓励使用功能性编程语言Scilla提供了一个很好的机会。伦敦正在成为一个欧洲区块链领导者和一个长期存在的经济中心,我们正在利用我们在伦敦的新基地以便寻求当地的教育伙伴关系来推动区块链教育和提高学生对Zilliqa的认识。其中一个合作关系是为期三个月的“区块链未来竞赛”,目标是牛津,剑桥和帝国理工等英国顶级大学。09、主网将于1月份发布,此次发布的关键步骤是什么?一旦主网上线,矿工们如何参与Zilliqa的挖矿?XD:我们最近发布了全功能测试网v3.0,它配备了我们的主网上所有的功能。据我们所知,这是世界上第一个实现了网络、交易和智能合约分片的完全成熟的测试网。矿工们能够严格测试这些功能是很重要的,在他们不断测试时,我们将能够添加必要的安全检查,以提高区块链的稳定性和安全性。我们的公开挖矿公告还向一个更大的开发者社区开放了我们的区块链,从而扩大了测试网络功能的开发者群体,以便我们在发布前可以继续改进。我们还正在开发更大规模的基础设施来帮助矿工迁移到我们的网络,以便在主网启动后挖掘Zilliqa。目前,矿工们可以参考我们的Github加入测试网挖矿,以帮助测试我们的基础设施。原文链接:https://coincentral.com/interview-zilliqa-team/

February 26, 2019 · 1 min · jiezi

现代 JavaScript 函数库 usuallyjs 的安装和使用

usuallyjsusuallyjs 是一个面向现代 Web 开发的 JavaScript 实用函数库。usuallyjs 基于 ES6 开发,抛弃了传统 Web 开发中 DOM 和 BOM 操作部分的内容,精选了一系列 Web 开发过程中最常用的、最实用的 JavaScript 函数。与 Vue、React、Angular等现代 Web 框架搭配使用,更好的服务于开发现代 Web 应用。GitHub文档安装和使用npm安装和使用通过 npm 使用如下命令安装:npm install –save-dev usuallyjs通过 es6 模块引用:import U from ‘usuallyjs’通过 node 模块引用:const U = require(‘usuallyjs’)浏览器安装和使用下载本存储库,在页面中通过 script 标签引入 dist 文件夹下的 usually.js 文件即可,建议使用压缩版本 usually.min.js。通过命名空间 U 调用相关的函数。如:<!DOCTYPE html><html> <head> <meta charset=“utf-8”> <title>usually浏览器安装和使用示例</title> <script src=“dist/usually.js”></script> </head> <body> <script> var a = U.random() </script> </body></html>浏览器兼容支持 IE9+ 和现代浏览器贡献在提出拉取请求之前,请务必阅读贡献指南。感谢所有为usuallyjs做出贡献的人!LICENSEMIT

February 26, 2019 · 1 min · jiezi

react源码ReactTreeTraversal.js之数据结构与算法

面试中,经常遇到的一个简单算法题:查找两个单链表的公共节点最近在读react源码的时候发现一个react树中对该算法的运用(见getLowestCommonAncestor函数),在此做简单的记录。git地址getParent在react树中获取当前实例节点的父节点实例//HostComponent组件对应的DOM,比如App的tag=3, 表示为类组件,其child为tag=5对应div元素。function getParent(inst) { do { inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. // That is depending on if we want nested subtrees (layers) to bubble // events to their parent. We could also go through parentNode on the // host node but that wouldn’t work for React Native and doesn’t let us // do the portal feature. } while (inst && inst.tag !== HostComponent); if (inst) { return inst; } return null;}getLowestCommonAncestor获取节点A与B的最近的公共祖先节点算法题:找到两个链表的公共节点export function getLowestCommonAncestor(instA, instB) { //获取子节点A在树中的深度 let depthA = 0; for (let tempA = instA; tempA; tempA = getParent(tempA)) { depthA++; } //获取子节点B在树中的深度 let depthB = 0; for (let tempB = instB; tempB; tempB = getParent(tempB)) { depthB++; } // If A is deeper, crawl up. // 如果A的高度高,那么A节点先往上走depthA - depthB个节点,最后同时走,直到父节点是同一个 while (depthA - depthB > 0) { instA = getParent(instA); depthA–; } // 如果B的高度高,那么B节点先往上走depthB - depthB个节点,最后同时走,直到父节点是同一个 // If B is deeper, crawl up. while (depthB - depthA > 0) { instB = getParent(instB); depthB–; } // Walk in lockstep until we find a match. // 现在,指针所处的位置的高度一致,可以同时往上查找,直到找到公共的节点 let depth = depthA; while (depth–) { if (instA === instB || instA === instB.alternate) { return instA; } instA = getParent(instA); instB = getParent(instB); } return null;}isAncestor判断A节点是否是B节点的祖先节点export function isAncestor(instA, instB) { while (instB) { if (instA === instB || instA === instB.alternate) { return true; } instB = getParent(instB); } return false;}getParentInstance对getParent的export封装:export function getParentInstance(inst) { return getParent(inst);}traverseTwoPhase对inst及其以上的树执行冒泡捕获的操作,执行fn。类似事件的冒泡捕获export function traverseTwoPhase(inst, fn, arg) { const path = []; //将inst的父节点入栈,数组最后的为最远的祖先 while (inst) { path.push(inst); inst = getParent(inst); } let i; //从最远的祖先开始向inst节点捕获执行fn for (i = path.length; i– > 0; ) { fn(path[i], ‘captured’, arg); } //从inst节点开始向最远的祖先节点冒泡执行fn for (i = 0; i < path.length; i++) { fn(path[i], ‘bubbled’, arg); }}traverseEnterLeave当关注点从from节点移出然后移入to节点的时候,在from执行执行类似移入移出的操作,from节点export function traverseEnterLeave(from, to, fn, argFrom, argTo) { const common = from && to ? getLowestCommonAncestor(from, to) : null; const pathFrom = []; while (true) { if (!from) { break; } if (from === common) { break; } const alternate = from.alternate; if (alternate !== null && alternate === common) { break; } pathFrom.push(from); from = getParent(from); } const pathTo = []; while (true) { if (!to) { break; } if (to === common) { break; } const alternate = to.alternate; if (alternate !== null && alternate === common) { break; } pathTo.push(to); to = getParent(to); } //以上代码将from节点到from与to节点的最近公共祖先节点(不包括公共祖先节点)push到pathFrom数组 //以上代码将to节点到from与to节点的最近公共祖先节点(不包括公共祖先节点)push到pathTo数组 // 以下代码用于对pathFrom冒泡,执行fn for (let i = 0; i < pathFrom.length; i++) { fn(pathFrom[i], ‘bubbled’, argFrom); } // 以下代码用于对pathTo捕获,执行fn for (let i = pathTo.length; i– > 0; ) { fn(pathTo[i], ‘captured’, argTo); }} ...

February 26, 2019 · 2 min · jiezi

java bean 对象属性复制框架BeanMapping-release_0.0.2-注解支持

BeanMapping为了更加灵活的指定映射方式,0.0.2 版本引入了 @BeanMapping 注解。注解的定义注解定义在 bean-mapping-api 模块中,bean-mapping-core 会默认引入此模块。package com.github.houbb.bean.mapping.api.annotation;import com.github.houbb.bean.mapping.api.core.ICondition;import com.github.houbb.bean.mapping.api.core.IConvert;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * <p> BeanMapping 注解 </p> * * <pre> Created: 2019/2/19 10:11 PM </pre> * <pre> Project: bean-mapping </pre> * * @author houbinbin * @since 0.1.0 /@Inherited@Documented@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface BeanMapping { /* * 字段的名称 * 如果不填,则默认使用字段的名称 * 1. 会将 source 的值赋值给 target 和当前 name 属性一致的对象。 * @return 名称 / String name() default “”; /* * 生效条件 * 1. 默认为生效 * 2. 当放在 source 字段上时,表示是否将值赋给 target 字段 * 当放在 target 字段上时,表示是否接受赋值。 * 3. source+target只有同时生效时,才会发生赋值。 * @return 具体的生效实现 / Class<? extends ICondition> condition() default ICondition.class; /* * 类型转换 * 1. 默认不进行转换 * 2. 为了确保转换的确定性+灵活性。对象中指定这个属性,不会改变对象的属性值和类型。 * 如果要改变原来的值,那么类型就会被限制的很多,无法足够的灵活。 * 3. 只有当 source 的值转换后可以设置给 target,才会将 source 转换后的值赋值给 target 对应属性,其他情况不会对值产生影响。 * @return 具体的转换实现 / Class<? extends IConvert> convert() default IConvert.class;}name 属性有时候 source 和 target 的字段名称可能不同,只需要通过这个属性,让二者保持一致即可。ICondition 接口用于指定赋值是否生效,可以实现目标对象有值就不被覆盖的常见需求。public interface ICondition { /* * 将原始信息转换为目标信息 * @param context 当前执行上下文 * @return 转换结果 / boolean condition(final IContext context);}IContext 上下文接口其中 IContext 是执行的上下文,便于获取到执行的相关属性。更加灵活的指定和实现我们的功能。IConvert 字段转化接口有时候我们希望对字段的值进行处理,比如日期/金额格式化,枚举值显示的处理等等。就可以借助这个接口,保证代码赋值的优雅性,提升代码的可复用性,更加符合 Open-Close 原则。/* * <p> 转换接口 </p> * 1. 所有的实现都应该提供默认构造器 * <pre> Created: 2019/2/19 10:15 PM </pre> * <pre> Project: bean-mapping </pre> * * @param <T> 目标泛型 * @author houbinbin * @since 0.1.0 /public interface IConvert<T> { /* * 将原始信息转换为目标信息 * @param context 当前执行上下文 * @return 转换结果 */ T convert(final IContext context);}拓展阅读属性复制框架-01-不同名称字段的指定赋值属性复制框架-02-自定义赋值生效的条件属性复制框架-03-自定义字段转换实现 ...

February 25, 2019 · 1 min · jiezi

ggit (git gui) --- 开发记录 (一)

ggit-npm-tool https://www.npmjs.com/package…文章后续更新,存入草稿时间长会被删, 希望谅解

February 24, 2019 · 1 min · jiezi

SpringBoot 填坑 | CentOS7.4 环境下,MySQL5.7 表时间字段默认值设置失效

微信公众号:一个优秀的废人如有问题或建议,请后台留言,我会尽力解决你的问题。前言如题,今天这篇是一个刚认识不久的小师弟的投稿。交谈中感觉技术水平与代码素养非常高,关键是才大二呀。那会我应该还在玩泥巴吧,真是后生可畏。问题描述我在本地端( windos 端,数据库版本 MySQL5.7、SpringBoot2.1.3、数据访问框架 JPA)测试代码时 current_timestamp 属性只要设有置默认值,就会自动生成数据的创建时间,与修改数据之后的修改时间。但是在 CentOS 服务器中。调用 JPA 中 save() 方法。字段却不会自动生成了。1、这是其中一张数据库的案例:CREATE TABLE user_info ( id int(32) NOT NULL AUTO_INCREMENT, username varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, password varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, shop_type int(11) NULL DEFAULT NULL COMMENT ‘店铺编号’, salt varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ‘盐’, status int(64) NOT NULL COMMENT ‘账号状态’, openid varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ‘微信openid’, create_time timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT ‘创建时间’, update_time timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT ‘修改时间’, PRIMARY KEY (id) USING BTREE, UNIQUE INDEX upe_seller_info_username(username) USING BTREE);从上面 SQL 示例可以注意到表字段,创建时间和更新时间设置了默认值 CURRENT_TIMESTAMP(0) 。2、这是发送的创建用户请求,里面的逻辑有 save 方法:3、这是在线上服务器报的错误问题排查前面我说了,我已经设置了字段有默认值的。。但是为什么在线上服务器居然没有自动生成。我百思不得其解,在本地端安然无恙,怎么线上环境炸了呢?而且我还在日志中发现一般都是 insert 中会出错误。尝试解决:首先我在 entity 层中删除了createtime,updatetime,果然不报空了。但是在我的 freemarker 上又必须有这个字段怎么办呢?解决问题在你的 createtime,updatetime 上分别加上 @CreatedDate 和 @LastModifiedDate 在 entity 类上加注解 @EntityListeners(AuditingEntityListener.class) 还要在你的启动类加上 @EnableJpaAuditing ,问题迎刃而解。entity类@Data@Entity@DynamicUpdate // 生成动态SQL语句,即在插入和修改数据的时候,语句中只包括要插入或者修改的字段。@EntityListeners(AuditingEntityListener.class)public class UserInfo { @Id @GeneratedValue private Integer id; private String username; private String password; //店铺编号 private Integer shopType; //加盐 private String salt; private Integer status; //卖家微信openid private String openid; //创建时间 @CreatedDate @JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”, timezone = “GMT+8”) private Date createTime; //更新时间 @LastModifiedDate @JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”, timezone = “GMT+8”) private Date updateTime;}启动类@SpringBootApplication@EnableSwagger2@EnableJpaAuditingpublic class ShipApplication { public static void main(String[] args) { SpringApplication.run(ShipApplication.class, args); }}至此,问题解决。注解解释@CreatedDate //表示该字段为创建时间时间字段,在这个实体被insert的时候,会设置值@LastModifiedDate //同理@EntityListeners(AuditingEntityListener.class) // JPA审计@EnableJpaAuditing//开启JPA审计我的思考我个人的理解是当我们添加这些注解后,JPA 的审计功能会把值再重复设置进 createtime,updatetime 这两个字段里面,第一遍是数据库层默认值,第二遍就是代码层设置的。后语如果本文对你哪怕有一丁点帮助,请帮忙点好看。你的好看是我坚持写作的动力。另外,关注之后在发送 1024 可领取免费学习资料。资料内容详情请看这篇旧文:Python、C++、Java、Linux、Go、前端、算法资料分享 ...

February 24, 2019 · 1 min · jiezi

GraphQL学习过程应该是这样的

记录一个从枯燥学习 GraphQL 的过程,到发现项目 Gitter,模仿项目 Github-Trending-API,最后做一个自己的学习项目 Github-Trending-GraphQL。 一开始我是这样想的,最后我是这样做的,复盘整个学习过程。 准备学习graphql 是什么? 在之前的项目中我们主要使用 graphql 来做已有接口数据的合并,这个主要处理已有 rest 相关服务接口的情况下,我们做了一个中间数据处理层。 最近在思考团队服务项目开发的时候,因为在开发中如果基于 rest 接口来开发的会,会定义很多路由。为了偷懒不去定义路由,于是决定在项目中使用 graphql (其实只是为了装B,我在项目中用了最新的XX技术),中间还有一些其他的思考。几个概念Graphql 模型有三种类型的操作。Query查询数据(R)。# standardquery { field}# shorthand{ fields}Mutation新增、更新或删除数据(CUD)。mutation { do( arguments ) { fields }}Objects表示可以访问的资源。# Repository 包含项目的内容 # Implements # Connections # FieldsImplements学不动了,省略….受其它项目启发在枯燥的文档学习过程中,中间看到一个博客是推荐自己的小程序 gitter,出于习惯抓了一下小程序的请求,发现了趋势排行是通过 github-trending-api.now.sh 获取的数据,接着就找到了这个 API 对应的项目 github-trending-api。 在这之前我也看过几次 GitHub GraphQL API,只是趋于时间与其他因素(懒),一直没有使用落实到实际的项目中。发现官方没有提供 Trending API,github-trending-api 项目新增了 V3 中的Trending API,我是不是可以模仿该项目提供一个 GraphQL API。 带着两个目的开始一个新项目:学习 GraphQL做一个开源项目初始化项目最简单的实现方式就是提供一个 GraphQL server,然后直接请求 github-trending-api.now.sh 。这种用法对于项目已有微服务的团队,可以利用中间服务层来合并数据请求,以及嵌套数据查询等。 GraphQL server 使用的是 Apollo Server,用它来创建一个 Node 服务,定义好 Schema,增加 resolver 解析函数。Type 如何定义在一开始学习的基础只是派上用场,GitHub Trending 主要提供两个方面,一个是 Repository ,另外一个是 Developer。type Repository { author: String contributors: [Contributor] currentPeriodStars: Int description: String forks: Int language: Lang name: String stars: Int url: String}Repository 中除了基本的 scalar type 还有两个是 contributor 和 language,一个数组数据,一个是对象,继续细分类型下去就得到了type Contributor { avatar: String url: String username: String}type Lang { name: String color: String}Developer 分析数据后一样得到一个数据结构type Developer { avatar: String name: String repository: RepositoryMini username: String url: String}其中项目仓库是一个对象数据,细分下来可以得到一个type RepositoryMini { description: String name: String url: String}Query 如何定义定义好了基本数据类型 Repository 和 Developer 以后,需要对外提供一个统一的 Query,于是得到了一个新的根数据类型type Query { repositories: [Repository], developers: [Developer]}实际的查询趋势过程中我们还会增加参数,一个参数是 language,一个参数 since,其中 since 只能取 daily、 weekly、 monthly ,但实际也能取其它值,只是默认的还是 daily。修改后得到了下面的结果type Query { repositories(language: String, since: String): [Repository], developers(language: String, since: String): [Developer]}如果要验证 since 只能取三个值中的一直,需要新增一个枚举类型type Query { repositories(language: String, since: Since): [Repository], developers(language: String, since: Since): [Developer]}enum Since { daily weekly monthly}如何优化 Query上述写法实际过程中可能还会有这样一个问题,如果要同时查询获得 Repository 和 Developer 的数据,需要按照筛选条件查询的适合,需要重复传递参数,再提升一下这两个类型实际是属于类型 Trending 的。新增一个类型type Trending { repositories: [Repository] developers: [Developer]}根查询 Query 也可以修改一下了type Query { trending(language: String, since: String): Trending}客户端发起查询请求按照最终我们定义好的数据结构,我们可以发起一个这样的 query{ Trending(language: “javascript”, since: “daily”) { repositories { name author description language { name color } forks stars contributors { avatar url username } currentPeriodStars url } developers { avatar name repository { url name description } username url } }}如果把 language 和 since 定义在 variables 中,写法就变成了下面这样# 以下请求只获取了趋势仓库名称# queryquery getTrending($language: String, $since: String) { trending(language: $language, since: $since) { repositories { name } }}# variables{ “language”: “javascript”, “since”: “daily”}query 和 variables 会作为 request payload 放置在 body 中,其中把自定义的操作方法 operationName 设置为 getTrendingfetch(“https://trending.now.sh”, { “credentials”: “omit”, “headers”: { “accept”: “/”, “accept-language”: “zh-CN,zh;q=0.9,en;q=0.8”, “content-type”: “application/json” }, “referrer”: “http://localhost:4000/”, “referrerPolicy”: “no-referrer-when-downgrade”, “body”: “{"operationName":"getTrending","variables":{"language":"javascript","since":"daily"},"query":"query getTrending($language: String, $since: String) {\n trending(language: $language, since: $since) {\n repositories {\n name\n }\n }\n}\n"}”, “method”: “POST”, “mode”: “cors”});服务端解析请求这里用的是 Apollo server,服务收到请求以后,会解析 body 参数。会按照嵌套依次调用 resolver 处理业务逻辑,首先会进入 trending ,接着同时执行 repository 和 developer。 按照根查询定义好的数据结构,tending 解析器会收到两个参数,language 和 since。repository 和 developer 也要使用这两个参数如何处理呢?// resolver{ Query: { trending(parent, args, context, info) { // args => { language: ‘’, since: ’’ } // parent 参数是可以接收到上层解析器的结果,我们可以把 trending 中收到的数据传递给子解析器 return { language, since } } }, Trending: { repositories(parent, args, context, info) { // parent => { language: ‘’, since: ’’ } }, developer(parent, args, context, info) { // parent => { language: ‘’, since: ’’ } }, }}解析器中需要做什么?解析器按照前文分析的数据,我们可以直接请求 github-trending-api.now.sh 数据接口拿到数据,这里我们本着学习为目的,GitHub Trending 是通过 SSR 输出的页面,数据只能自己分析网页,抓取html页面以后分析页面结构获得自己需要的数据。export async function fetchRepository() { // 分析html}export async function fetchDeveloper() { // 分析html}export async function fetchLanguage() { // 分析html}具体的分析 html 过程不做分析,使用了 cheerio,用法类似 JQuery。这中间也会有一些需要注意的问题请求过程很慢。 每次请求都会再次请求 Github Trending 的页面,然后还要分析页面,这个过程其实是比较费时的。我们如果把请求分析后的数据按照查询条件缓存起来,下一次请求直接就从缓存中拿数据,这样就快很多。(仓库和开发者趋势会隔段时间更新,我们缓存一小时;语言变化小,我们缓存了一天的时间)语言包缓存。 请求仓库和开发者的适合,检测语言缓存是否存在,不存在先缓存一次,后续再次请求仓库和开发者或者直接请求语言包就会直接命中缓存有了缓存就可能出现缓存失效的问题,我们新增一个刷新缓存的方法,可以按照指定键名来更新缓存,也可以不传递参数清理全部缓存。如何清理缓存?GraphQL 根处理方法除了 Query ,还有一个 Mutation。对应到的数据库增删改查上面的话,Query 对应的是 R,Mutation 对应的是 CUD。我们要新增的 refresh 的操作是删除缓存,主要针对仓库和开发者缓存,清理以后我们只关心成功失败与否,所以这里我们可以返回一个布尔值type Mutation { refresh(key: String, language: String, since: String): Boolean}解析器中也需要添加对应的处理方法{ Mutation: { refresh(parent, args, context, info) { // do something } }}回顾一下从一开始的需求分析,我们需要开发一个 Github Trending GraphQL API。我们利用了之前学习的 GraphQL 的基础知识,也熟悉了 GraphQL 的工具 Apollo Server,很方便的开发出了对应的API,后续为了优化请求,我们新增了缓存策略,以及清除缓存策略。 到这里我们的项目 github-trending-graphql 就可以提交到 GitHub 仓库中了,对于一个完美的开源项目还有很多事情要做,但是对于一个 GraphQL 的示例差不多已经可以使用了。 一上来就直接看代码是枯燥的,于是我们还需要部署一个 Demo,这样带着使用来熟悉就更容易让人理解了。如何简单的部署 Demo 又成为了一个问题?如何部署示例trending.now.sh 的部署看域名应该就能猜到使用的是 now 的无服务部署方式。使用方式文档已经讲述的很清楚了。但这中间也还是需要注意一些细节对于项目部署,我们需要首先在项目根目录建立一个 now.json{ “version”: 2, “alias”: [“trending.now.sh”], “builds”: [{ “src”: “src/server.js”, “use”: “@now/node-server” }], “routes”: [{ “src”: “/”, “dest”: “/src/server.js” }]}alias 这里配置上 now.sh 的别名是不会直接生效的,这里只是方便备忘。server.js 是一个需要执行的文件,于是我们将 version 设置为 2,接下来我们就可以在配置中添加 builds 了,对于普通 js 可指定文件使用 @now/node ,这里的 server.js 是开启一个 Node 服务,所以需要使用 @now/node-server。 部署成功以后我们获得了一个 github-trending-graphql-[hash].now.sh 的项目访问地址,如果要访问到项目的实际功能,还需要点开两次两次获得项目功能地址 github-trending-graphql-[hash].now.sh/src/server.js ,如果要直接使用域名直接访问功能,我们这里就需要添加上述配置 route。 每一次部署都会产生一个新的镜像,也会得到一个新的二级域名,如果我们要分享出去无论是自己部署还是用户使用体验都不是很好,我们可以为自己的项目设置一个别名,这里我们为当前项目设置的别名就是 trending.now.sh 。 每次部署的时候我们需要做的工作就是 now && now alias ,now alias 需要指定当前部署获得的项目域名,以及需要设置的别名,$(now) 可以获得部署后获得的域名,于是上述命名就修改成 now alias $(now) trending.now.sh 了,添加 package.json 中,每次部署只需要执行一下 npm run now 。成果展示github trending graphql apionline demo相关项目github trending rest api ...

February 23, 2019 · 3 min · jiezi

java bean 对象属性复制框架BeanMapping-01-入门案例

项目简介Bean-Mapping 用于 java 对象属性赋值。项目中经常需要将一个对象的属性,赋值到另一个对象中。常见的工具有很多,但都多少不够简洁,要么不够强大。特性支持对象属性的浅拷贝变更日志变更日志快速开始准备JDK1.8 及其以上版本Maven 3.X 及其以上版本maven 项目依赖<dependency> <groupId>com.github.houbb</groupId> <artifactId>bean-mapping-core</artifactId> <version>0.0.1</version></dependency>核心类说明BeanUtil提供一个简单的静态方法 copyProperties。/** * 复制属性 * 将 source 中的赋值给 target 中名称相同,且可以赋值的类型中去。类似于 spring 的 BeanUtils。 * @param source 原始对象 * @param target 目标对象 /public static void copyProperties(final Object source, Object target)测试代码参考详情参见 bean-mapping-test 模块下的测试代码。示例代码对象的定义BaseSource.java & BaseTarget.java其中 BaseSource 对象和 BaseTarget 对象的属性是相同的。public class BaseSource { /* * 名称 / private String name; /* * 年龄 / private int age; /* * 生日 / private Date birthday; /* * 字符串列表 / private List<String> stringList; //getter & setter}属性赋值测试案例我们构建 BaseSource 的属性,然后调用BeanUtil.copyProperties(baseSource, baseTarget);类似于 spring BeanUtils 和 Apache BeanUtils,并验证结果符合我们的预期。 /* * 基础测试 / @Test public void baseTest() { BaseSource baseSource = buildBaseSource(); BaseTarget baseTarget = new BaseTarget(); BeanUtil.copyProperties(baseSource, baseTarget); // 断言赋值后的属性和原来相同 Assertions.assertEquals(baseSource.getAge(), baseTarget.getAge()); Assertions.assertEquals(baseSource.getName(), baseTarget.getName()); Assertions.assertEquals(baseSource.getBirthday(), baseTarget.getBirthday()); Assertions.assertEquals(baseSource.getStringList(), baseTarget.getStringList()); } /* * 构建用户信息 * @return 用户 */ private BaseSource buildBaseSource() { BaseSource baseSource = new BaseSource(); baseSource.setAge(10); baseSource.setName(“映射测试”); baseSource.setBirthday(new Date()); baseSource.setStringList(Arrays.asList(“1”, “2”)); return baseSource; } ...

February 23, 2019 · 1 min · jiezi

使用Hexo框架搭建博客,并部署到github上

开发背景:年后回来公司业务不忙,闲暇时间了解一下node的使用场景,一篇文章吸引了我15个Nodejs应用场景,然后就被这个hexo框架吸引了,说时迟,那时快,赶紧动手搭建起来,网上找了好多资料一天时间才搭建完成,我的博客地址:博客,记录一下过程,以便以后学习。开始搭建学习新框架的一般步骤:中文文档撸一遍,跟着做(Hexo中文文档),一般都会有各种问题出现,当然直接成功的也有,很不幸,我就是出现问题的那一类,没关系,出现问题,解决问题的过程,才能学到更多东西;上网找一些hexo使用的教程,继续弄;这个时候要是再有问题就是很难解决的有针对性的问题了,继续上网找相关的解决办法;网上资源真的很多,很好用,只要想学没有找不到的东西,哈哈哈…一、安装前提:既然是node框架,肯定前提是你已经安装过Node.js(下载地址),另外还需要你安装Git(下载地址);如果你已经成功安装了上述程序后,接下来就是hexo的安装:$ npm install -g hexo-cli安装完成以后,需要初始化一下项目,执行下列命令:$ hexo init$ npm install完成以后,项目大概目录就是这样的:.├── _config.yml├── package.json├── scaffolds├── source| ├── _drafts| └── _posts└── themes_config.yml网站的配置信息,可以在此配置大部分的参数。后面发布到github上面时,有用到这个文件;package.json应用程序的信息。文件的其他部分的详细解释请看文档,此处只是记录一下搭建以及发布的过程,具体写文章的步骤,先不进行过多说明;接下来可以在本地启服务来查看一下项目的初始状态:$ npm install hexo-server –save$ hexo server效果大概就是下面的样子:我稍微修改了一下文字配置,可能你的会跟我的有点不一样,项目能启动就是成功了;二、发布到github并设置成个人博客1、github上新建一个仓库登录自己的github后,在界面右上角用户信息点击左边的加号,新建一个repository:然后给新建的仓库起个名字,注意:这个名字必须跟用户名一致,github才会默认设置成用户的博客:项目建好以后,就是一些信息的设置:设置页面里面有分支选项,如果有master分支,会默认成博客的首选代码;2、将本地搭建好的hexo发布到github上:将本地代码上传到github上的方法有很多:可以用Github Desktop,简单直观,但是需要把之前我们搭建好的项目生成的文件放到GitHub Desktop指定的位置,再上传,感觉不那么智能,还有点麻烦,所以我选择planB,耶!我可真是个小机灵鬼…下面是在项目中生成静态文件的命令:$ hexo generate简写,结果是一样的$ hexo g执行完以上代码,会在项目的根目录下生成public文件夹,选择planA的童鞋就可以将里面的所有文件用GitHub Desktop上传到github上了;而另外一种,就是在当前项目直接远程连接自己的github上传文件,这会涉及到SSH(关于SSH是什么,网上有很多详细说明,可以自己查找学习)安装插件:npm install hexo-deployer-git –save修改网站配置文件_config.yml,添加deploy信息:deploy: type: git repo: git@github.com:wjlilh/wjlilh.github.io.git branch: master 上面的repo的配置信息,替换成自己的项目名字生成SSH key:按照网上的教程生成ssh key的时候是直接ssh-add,但是失败了,调查问题,发现原因是因为,我是第一次使用ssh-agent代理,第一次需要首先执行以下命令,以后就不需要了(具体原来请参考此处链接):$ ssh-agent bash以上命令回车,启动进程,后再输入命令:$ ssh-add ~/.ssh/id_rsa按照提示操作输入密码,这样就在c盘对应位置生成了ssh-key;配置github账户的ssh-key打开id_rsa.pub文件将一整串公钥拷贝下来进入你的github账户设置,在ssh and GPG keys中新增一个ssh key,如下 title随意,key填id_rsa.pub文件中内容,保存即可;验证是否连接成功:$ ssh -T git@github.com出现下面的语句说明你的ssh key已经配置好了Hi wispyoureyes! You’ve successfully authenticated, but GitHub does not provide shell access.ok,到了这一步,本地跟远程github的连接已经建立,在项目中,直接生成静态文件,上传就可以了:$ hexo clean //清除缓存文件db.json和已生成的静态文件public$ hexo g //生成网站静态文件到默认设置的public文件夹$ hexo d //部署网站到设定的仓库这样就完成了个人博客的github部署,直接打开过程中设置的地址就可以查看了,我的是:https://wjlilh.github.io/ ...

February 22, 2019 · 1 min · jiezi

SpringBoot 实战 (十) | 声明式事务

微信公众号:一个优秀的废人如有问题或建议,请后台留言,我会尽力解决你的问题。前言如题,今天介绍 SpringBoot 的 声明式事务。Spring 的事务机制所有的数据访问技术都有事务处理机制,这些技术提供了 API 用于开启事务、提交事务来完成数据操作,或者在发生错误时回滚数据。而 Spring 的事务机制是用统一的机制来处理不同数据访问技术的事务处理,Spring 的事务机制提供了一个 PlatformTransactionManager 接口,不同的数据访问技术的事务使用不同的接口实现,如下表:数据访问技术实现JDBCDataSourceTransactionManagerJPAJPATransactionManagerHibernateHibernateTransactionManagerJDOJdoTransactionManager分布式事务JtaTransactionManager声明式事务Spring 支持声明式事务,即使用注解来选择需要使用事务的方法,他使用 @Transactional 注解在方法上表明该方法需要事务支持。被注解的方法在被调用时,Spring 开启一个新的事务,当方法无异常运行结束后,Spring 会提交这个事务。如:@Transactionalpublic void saveStudent(Student student){ // 数据库操作}注意,@Transactional 注解来自于 org.springframework.transcation.annotation 包,而不是 javax.transaction。Spring 提供一个 @EnableTranscationManagement 注解在配置类上来开启声明式事务的支持。使用了 @EnableTranscationManagement 后,Spring 容器会自动扫描注解 @Transactional 的方法与类。@EnableTranscationManagement 的使用方式如下:@Configuration@EnableTranscationManagement public class AppConfig{}注解事务行为@Transactional 有如下表所示的属性来定制事务行为。属性含义propagation事务传播行为isolation事务隔离级别readOnly事务的读写性,boolean型timeout超时时间,int型,以秒为单位。rollbackFor一组异常类,遇到时回滚。(rollbackFor={SQLException.class})rollbackForCalssName一组异常类名,遇到回滚,类型为 string[]noRollbackFor一组异常类,遇到不回滚norollbackForCalssName一组异常类名,遇到时不回滚。类级别使用 @Transactional@Transactional 不仅可以注解在方法上,还可以注解在类上。注解在类上时意味着此类的所有 public 方法都是开启事务的。如果类级别和方法级别同时使用了 @Transactional 注解,则使用在类级别的注解会重载方法级别的注解。SpringBoot 的事务支持自动配置的事务管理器在使用 JDBC 作为数据访问技术时,配置定义如下:@Bean@ConditionalOnMissingBean@ConditionalOnBean(DataSource.class)public PlatformTransactionManager transactionManager(){ return new DataSourceTransactionManager(this.dataSource)}在使用 JPA 作为数据访问技术时,配置定义如下:@Bean@ConditionalOnMissingBean(PlatformTransactionManager.class)public PlatformTransactionManager transactionManager(){ return new JpaTransactionManager()}自动开启注解事务的支持SpringBoot 专门用于配置事务的类为 org.springframework.boot.autoconfigure.transcation.TransactionAutoConfiguration,此配置类依赖于 JpaBaseConfiguration 和 DataSourceTransactionManagerAutoConfiguration。而在 DataSourceTransactionManagerAutoConfiguration 配置里还开启了对声明式事务的支持,代码如下:@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)@Configuration@EnableTransactionManagementprotected static class TransactionManagementConfiguration{}所以在 SpringBoot 中,无须显式开启使用 @EnableTransactionManagement 注解。实战演示如何使用 Transactional 使用异常导致数据回滚与使用异常导致数据不回滚。准备工作:SpringBoot 2.1.3JDK 1.8IDEApom.xml 依赖:<?xml version=“1.0” encoding=“UTF-8”?><project xmlns=“http://maven.apache.org/POM/4.0.0" xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!– lookup parent from repository –> </parent> <groupId>com.nasus</groupId> <artifactId>transaction</artifactId> <version>0.0.1-SNAPSHOT</version> <name>transaction</name> <description>transaction Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!– JPA 相关 –> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!– web 启动类 –> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!– mysql 连接类 –> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!– lombok 插件,简化实体代码 –> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.20</version> </dependency> <!– 单元测试 –> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>代码注释很清楚,没啥好说的。application.yaml 配置:spring: # \u6570\u636E\u5E93\u76F8\u5173 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=true username: root password: 123456 # jpa \u76F8\u5173 jpa: hibernate: ddl-auto: update # ddl-auto:\u8BBE\u4E3A create \u8868\u793A\u6BCF\u6B21\u90FD\u91CD\u65B0\u5EFA\u8868 show-sql: true实体类:import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@Entity@AllArgsConstructor@NoArgsConstructorpublic class Student { @Id @GeneratedValue private Integer id; private String name; private Integer age;}dao 层import com.nasus.transaction.domain.Student;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.stereotype.Repository;@Repositorypublic interface StudentRepository extends JpaRepository<Student, Integer> {}service 层import com.nasus.transaction.domain.Student;public interface StudentService { Student saveStudentWithRollBack(Student student); Student saveStudentWithoutRollBack(Student student);}实现类:import com.nasus.transaction.domain.Student;import com.nasus.transaction.repository.StudentRepository;import com.nasus.transaction.service.StudentService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;@Servicepublic class StudentServiceImpl implements StudentService { @Autowired // 直接注入 StudentRepository 的 bean private StudentRepository studentRepository; // 使用 @Transactional 注解的 rollbackFor 属性,指定特定异常时,触发回滚 @Transactional(rollbackFor = {IllegalArgumentException.class}) @Override public Student saveStudentWithRollBack(Student student) { Student s = studentRepository.save(student); if (“高斯林”.equals(s.getName())){ //硬编码,手动触发异常 throw new IllegalArgumentException(“高斯林已存在,数据将回滚”); } return s; } // 使用 @Transactional 注解的 noRollbackFor 属性,指定特定异常时,不触发回滚 @Transactional(noRollbackFor = {IllegalArgumentException.class}) @Override public Student saveStudentWithoutRollBack(Student student) { Student s = studentRepository.save(student); if (“高斯林”.equals(s.getName())){ throw new IllegalArgumentException(“高斯林已存在,数据将不会回滚”); } return s; }}代码注释同样很清楚,没啥好说的。controller 层import com.nasus.transaction.domain.Student;import com.nasus.transaction.service.StudentService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/student”)public class StudentController { // 注入 studentservice 的 bean @Autowired private StudentService studentService; // 测试回滚情况 @PostMapping("/withRollBack”) public Student saveStudentWithRollBack(@RequestBody Student student){ return studentService.saveStudentWithRollBack(student); } // 测试不回滚情况 @PostMapping("/withOutRollBack”) public Student saveStudentWithoutRollBack(@RequestBody Student student){ return studentService.saveStudentWithoutRollBack(student); }}Postman 测试结果为了更清楚地理解回滚,以 debug (调试模式) 启动程序。并在 StudentServiceImpl 的 saveStudentWithRollBack 方法上打上断点。测试前数据库结果:Postman 测试回滚debug 模式下可见数据已保存,且获得 id 为 1。:继续执行抛出异常 IllegalArgumentException,将导致数据回滚:测试后数据库结果:并无新增数据,回滚成功。Postman 测试不回滚测试前数据库结果:遇到 IllegalArgumentException 异常数据不会回滚:测试后数据库结果:新增数据,数据不回滚。源码下载https://github.com/turoDog/Demo/tree/master/springboot_transaction_demo后语以上为 SpringBoot 声明式事务的教程。最后,对 Python 、Java 感兴趣请长按二维码关注一波,我会努力带给你们价值,如果觉得本文对你哪怕有一丁点帮助,请帮忙点好看,让更多人知道。另外,关注之后在发送 1024 可领取免费学习资料。资料内容详情请看这篇旧文:Python、C++、Java、Linux、Go、前端、算法资料分享 ...

February 21, 2019 · 2 min · jiezi

这是一个爬虫—爬取天眼查网站的企业信息

爬虫简介这是一个在未登录的情况下,根据企业名称搜索,爬取企业页面数据的采集程序注意: 这是一个比较简单的爬虫,基本上只用到了代理,没有用到其他的反反爬技术,不过由于爬取的数据比较多,适合刷解析技能的熟练度,所以高手勿进代码已经上传到GitHub上,有用还请给个星python版本:python2.7编码工具:pycharm数据存储:mysql爬虫结构:广度爬虫爬虫思路:先获取需要采集信息的公司:从数据库中获取获取字段:etid,etname将获取的数据存储的状态表中从状态表中获取数据,并更新状态表拼接初始URL:将etname和初始url进行拼接,获得初始网址将初始url放到一个列表中,获取HTML的时候如何出错,将出错的url放到另一个列表中,进行循环获取请求解析初始一级页面:验证查询的公司是否正确(??)获取二级页面url将二级url放到一个列表中,获取HTML的时候如何出错,将出错的url放到另一个列表中,进行循环获取请求解析二级页面:获取的信息待定将公司的信息存储到数据库中:建表存储信息所建的表:企业主要信息: et_host_info工商信息: et_busi_info分支机构信息: et_branch_office软件著作权信息: et_container_copyright_info网站备案信息: et_conrainer_icp_info对外投资信息: et_foreign_investment_info融资信息: et_rongzi_info股东信息: et_stareholder_info商标信息: et_trademark_info微信公众号信息:et_wechat_list_info状态表: et_name_status看一下部分的结果图:

February 21, 2019 · 1 min · jiezi

Mac/Linux 安装中文版 man 帮助命令

一份攻城狮笔记有哪些鲜为人知,但是很有意思的网站?每天搜集 Github 上优秀的项目一些有趣的民间故事超好用的谷歌浏览器、Sublime Text、Phpstorm、油猴插件合集linux 环境安装macOS 环境安装编译工具安装因为需要编译安装,所以你电脑上需要有编译工具,运行下面两个命令安装$ brew install automake$ brew install opencc安装# 进入下载目录$ cd ~/Downloads/# 下载最新版本的源码包$ wget https://github.com/man-pages-zh/manpages-zh/archive/v1.6.3.3.tar.gz# 解压源码包(atool命令,推荐安装这个工具,统一所有压缩文档的命令)$ atool -x v1.6.3.3.tar.gz# 或者使用这个命令解压$ tar zxvf v1.6.3.3.tar.gz# 进入源码包文件夹$ cd manpages-zh-1.6.3.2/# 编译安装 1$ autoreconf –install –force# 编译安装 2$ ./configure# 编译安装 3$ sudo make# 编译安装 4$ sudo make install# 配置别名(如果是 zsh 对应处理即可)$ echo “alias cman=‘man -M /usr/local/share/man/zh_CN’” >> ~/.bash_profile# 使别名生效$ source ~/.bash_profile# 我们就安装上了中文版本的 man 工具了,但是运行命令会发现乱码。cman ls安装 groff 新版本解决中文乱码的问题# 进入下载目录$ cd ~/Downloads/# 下载1.22版本的源码包$ wget http://git.savannah.gnu.org/cgit/groff.git/snapshot/groff-1.22.tar.gz# 解压$ atool -x groff-1.22.tar.gz# 进入目录$ cd groff-1.22# 编译安装$ ./configure$ sudo make$ sudo make install# 打开配置文件$ sudo vim /etc/man.conf# 进入编辑器之后,在文件末尾添加NROFF preconv -e UTF8 | /usr/local/bin/nroff -Tutf8 -mandoc -c# 保存退出# 运行命令,完美解决乱码问题cman ls ...

February 21, 2019 · 1 min · jiezi

原生JavaScript 瀑布流 实现 zx-waterfall

源码地址: https://github.com/capricornc…使用说明Install zx-waterfall using npmnpm i –save zx-waterfallES6+import ZxWaterfall from ‘zx-waterfall’const waterfall = new ZxWaterfall({ // HTMLElement, waterfall items’s outer container container: document.getElementById(‘zxWaterfall’), // children item selector, eg. ‘.item-container’ itemSelector: ‘.item-wrapper’, // item’s spacing, unit px gutter: 20, // item’s width itemWidth: 300})// resetwaterfall.reset()// loaMediaswaterfall.loadMedia([‘http://xx.com/aaa.jpg’]).then(_ => { // change waterfall.change()})browser<script src=“path/zx-waterfall.min.js”></script>demohttps://capricorncd.github.io…注意container ’s style must be style.position=relative|absolute|fixed参数optionscontainer: HTMLElement瀑布流外容器.containerWidth: Number瀑布流宽度,如果初始化时外容器未隐藏状态则需使用该参数.默认获取外容器宽度.itemSelector: String子元素选择器,比如 样式名’.item-container’.gutter: Number元素间的间隔.verticalGutter: Number元素间垂直方向间隔,默认使用gutter值.itemWidth: Number元素宽度, 默认 300, 会根据容器宽度自动调整.forceItemWidth: Boolean强制元素宽度,即使用itemWidth作为宽度值,默认 false.align: String, Optional value left|center|right强制宽度时,元素显示靠边位置,默认 center.方法reset()重置瀑布流初始值loadMeida(array)预加载列表数据中的image媒体元素.array: [‘http://a.com/1.jpg’, ‘http://a.com/2.jpg’]@return promisechange()列表数据改变后后,通知瀑布流更新元素位置.源码/** * preload image * @param url * @param handler /function loadImage (url, handler) { let $el = document.createElement(‘img’) $el.src = url $el.onload = handler $el.onerror = handler $el = null}/* * to int * @param m * @returns {number} /function int (m) { let n = parseInt(m) return isNaN(n) ? 0 : n}/* * convert pseudoArray to array * @param pseudoArray * @param index * @returns {T[]} /function slice (pseudoArray, index) { return Array.prototype.slice.call(pseudoArray, int(index))}// default optionsconst DEF_OPTIONS = { // HTMLElement, waterfall items’s outer container container: null, // container’s width, container are hidden when initialized // default get container offsetWidth when it’s visible containerWidth: 0, // children item selector, eg. ‘.item-container’ itemSelector: ‘’, // item’s spacing, unit px gutter: 20, // item’s vertical spacing, default use gutter’s value verticalGutter: 0, // item’s width itemWidth: 300, // force item width forceItemWidth: false, // Horizontal align when forceItemWidth is true align: ‘center’}/* * ZxWaterfall /class ZxWaterfall { /* * constructor * @param opts / constructor (opts) { opts = Object.assign({}, DEF_OPTIONS, opts) // check container if (!opts.container || opts.container.nodeType !== 1) { throw new TypeError(Instancing parameter 'container' is not HTMLElement.) } // check itemSelector if (!opts.itemSelector || typeof opts.itemSelector !== ‘string’) { throw new TypeError(Instancing parameter 'itemSelector' is null or is't a string.) } // check verticalGutter if (!opts.verticalGutter) { opts.verticalGutter = opts.gutter } // item number this.count = 0 this.opts = opts this._init() // clone this.reset this._resetClone = this.reset.bind(this) window.addEventListener(‘resize’, this._resetClone) } /* * initialization * @private / _init () { let opts = this.opts // container width let containerWidth = int(opts.containerWidth) || opts.container.offsetWidth // column number let columnNum = Math.floor(containerWidth / (opts.itemWidth + opts.gutter)) // opts.itemWidth when opts.forceItemWidth = true // else use compute new width this.itemWidth = opts.forceItemWidth ? opts.itemWidth : (containerWidth - (columnNum + 1) * opts.gutter) / columnNum // column current height array this.columns = Array(columnNum) this.columns.fill(0, 0) // offset left when forceItemWidth=true this.offsetLeft = 0 if (opts.forceItemWidth) { let residualSpaceWidth = containerWidth - (this.itemWidth + opts.gutter) * columnNum - opts.gutter switch (opts.align) { case ‘center’: this.offsetLeft = residualSpaceWidth / 2 break case ‘right’: this.offsetLeft = residualSpaceWidth break } } } /* * set items position * @private / _setPosition () { let opts = this.opts // get new item elements let $childs = slice(opts.container.querySelectorAll(opts.itemSelector), this.count) // console.log(this.count, $childs) let len = $childs.length // reset this.count value this.count += len // handle new $item let i, $item for (i = 0; i < len; i++) { $item = $childs[i] if (!$item) continue $item.style.position = ‘absolute’ $item.style.width = this.itemWidth + ‘px’ $item.style.display = ‘inline-block’ // get columns min value let min = Math.min.apply(null, this.columns) let index = this.columns.findIndex(val => val === min) // set $item position $item.style.top = ${min + opts.verticalGutter}px $item.style.left = ${this.offsetLeft + (this.itemWidth + opts.gutter) * index + opts.gutter}px // reset waterfall current column height value let itemHeight = $item.offsetHeight this.columns[index] = min + itemHeight + opts.verticalGutter // update container new min height style // opts.container.style.minHeight = Math.max.apply(null, this.columns) + opts.verticalGutter + ‘px’ } } /* * container’s items number change / change () { // reset postion, when new item element append to container, or remove this._setPosition() } /* * reset / reset () { this.count = 0 this._init() this._setPosition() } /* * preload media items * @param arr media source urls array * @returns {Promise<any>} / loadMedia (arr) { return new Promise(resolve => { if (Array.isArray(arr) && arr.length) { let len = arr.length let count = 0 / eslint-disable / arr.forEach(url => { loadImage(url, () => { count++ if (len === count) resolve() }) }) } else { resolve() } }) } /* * destroy * removeEventListener window resize */ destroy () { window.removeEventListener(‘resize’, this._resetClone) }}export default ZxWaterfalldemo: https://github.com/capricornc… ...

February 19, 2019 · 4 min · jiezi

Kubernetes的共享GPU集群调度

问题背景全球主要的容器集群服务厂商的Kubernetes服务都提供了Nvidia GPU容器调度能力,但是通常都是将一个GPU卡分配给一个容器。这可以实现比较好的隔离性,确保使用GPU的应用不会被其他应用影响;对于深度学习模型训练的场景非常适合,但是如果对于模型开发和模型预测的场景就会比较浪费。 大家的诉求是能够让更多的预测服务共享同一个GPU卡上,进而提高集群中Nvidia GPU的利用率。而这就需要提供GPU资源的划分,而这里GPU资源划分的维度指的就是GPU显存和Cuda Kernel线程的划分。通常在集群级别谈支持共享GPU,通常是两件事情:1.调度 2.隔离,我们这里主要讨论的是调度,隔离的方案未来会基于Nvidia的MPS来实现。而对于细粒度的GPU卡调度,目前Kubernetes社区并没有很好的方案,这是由于Kubernetes对于GPU这类扩展资源的定义仅仅支持整数粒度的加加减减,无法支持复杂资源的分配。比如用户希望使用Pod A占用半张GPU卡,这在目前Kubernetes的架构设计中无法实现资源分配的记录和调用。这里挑战是多卡GPU共享是实际矢量资源问题,而Extened Resource是标量资源的描述。针对此问题,我们设计了一个outoftree的共享GPU调度方案,该方案依赖于Kubernetes的现有工作机制:Extended Resource定义Scheduler Extender机制Device Plugin机制用户场景作为集群管理员,我想提高集群的GPU使用率;在开发过程中,多个用户共享模型开发环境作为应用开发人员,我希望能够同时在Volta GPU上运行多个推理任务目标能够让使用者通过API描述对于一个可共享资源的申请, 并能实现该种资源的调度非目标不支持该共享资源的隔离不支持超卖设计原则明确问题简化设计,第一步只负责调度和部署,后续再实现运行时显存管控。有很多的客户明确的诉求是首先可以支持多AI应用可以调度到同一个GPU上,他们可以接受从应用级别控制显存的大小,利用类似gpu_options.per_process_gpu_memory_fraction控制应用的显存使用量。那我们要解决的问题就先简化到以显存为调度标尺,并且把显存使用的大小以参数的方式传递给容器内部。不做侵入式修改本设计中不会修改Kubernetes核心的Extended Resource的设计, Scheduler的实现,Device Plugin的机制以及Kubelet的相关设计。重用Extended Resource描述共享资源的申请API。这样的好处在于提供一个可以移植的方案,用户可以在原生Kubernetes上使用这个方案。按显存和按卡调度的方式可以在集群内并存,但是同一个节点内是互斥的,不支持二者并存;要么是按卡数目,要么是按显存分配。详细设计前提:依旧延用Kubernetes Extended Resource定义,但是衡量维度最小单位从1个GPU卡变为GPU显存的MiB。如果所节点使用的GPU为单卡16GiB显存,它对应的资源就是16276MiB由于用户对于共享GPU的诉求在于模型开发和模型预测场景,在此场景下,用户申请的GPU资源上限不会超过一张卡,也就是申请的资源上限为单卡而我们的工作首先是定义了两个新的Extended Resource: 第一个是gpu-mem, 对应的是GPU显存;第二个是gpu-count,对应的是GPU卡数。 通过两个标量资源描述矢量资源, 并且结合这一资源,提供支持共享GPU的工作机制。下面是基本的架构图:核心功能模块:GPU Share Scheduler Extender: 利用Kubernetes的调度器扩展机制,负责在全局调度器Filter和Bind的时候判断节点上单个GPU卡是否能够提供足够的GPU Mem,并且在Bind的时刻将GPU的分配结果通过annotation记录到Pod Spec以供后续Filter检查分配结果。GPU Share Device Plugin: 利用Device Plugin机制,在节点上被Kubelet调用负责GPU卡的分配,依赖scheduler Extender分配结果执行。具体流程:1. 资源上报GPU Share Device Plugin利用nvml库查询到GPU卡的数量和每张GPU卡的显存, 通过ListAndWatch()将节点的GPU总显存(数量 显存)作为另外Extended Resource汇报给Kubelet; Kubelet进一步汇报给Kubernetes API Server。 举例说明,如果节点含有两块GPU卡,并且每块卡包含16276MiB,从用户的角度来看:该节点的GPU资源为16276 2 = 32552; 同时也会将节点上的GPU卡数量2作为另外一个Extended Resource上报。2. 扩展调度GPU Share Scheduler Extender可以在分配gpu-mem给Pod的同时将分配信息以annotation的形式保留在Pod spec中,并且在过滤时刻根据此信息判断每张卡是否包含足够可用的gpu-mem分配。2.1 Kubernetes默认调度器在进行完所有过滤(filter)行为后会通过http方式调用GPU Share Scheduler Extender的filter方法, 这是由于默认调度器计算Extended Resource时,只能判断资源总量是否有满足需求的空闲资源,无法具体判断单张卡上是否满足需求;所以就需要由GPU Share Scheduler Extender检查单张卡上是否含有可用资源。以下图为例, 在由3个包含两块GPU卡的节点组成的Kubernetes集群中,当用户申请gpu-mem=8138时,默认调度器会扫描所有节点,发现N1所剩的资源为 (16276 * 2 - 16276 -12207 = 4069 )不满足资源需求,N1节点被过滤掉。 而N2和N3节点所剩资源都为8138MiB,从整体调度的角度看,都符合默认调度器的条件;此时默认调度器会委托GPU Share Scheduler Extender进行二次过滤,在二次过滤中,GPU Share Scheduler Extender需要判断单张卡是否满足调度需求,在查看N2节点时发现该节点虽然有8138MiB可用资源,但是落到每张卡上看,GPU0和分别GPU1只有4069MiB的可用资源,无法满足单卡8138MiB的诉求。而N3节点虽然也是总共有8138MiB可用资源,但是这些可用资源都属于GPU0,满足单卡可调度的需求。由此,通过GPU Share Scheduler Extender的筛选就可以实现精准的条件筛选。2.2 当调度器找到满足条件的节点,就会委托GPU Share Scheduler Extender的bind方法进行节点和Pod的绑定,这里Extender需要做的是两件事情以binpack的规则找到节点中最优选择的GPU卡id,此处的最优含义是对于同一个节点不同的GPU卡,以binpack的原则作为判断条件,优先选择空闲资源满足条件但同时又是所剩资源最少的GPU卡,并且将其作为ALIYUN_COM_GPU_MEM_IDX保存到Pod的annotation中;同时也保存该Pod申请的GPU Memory作为ALIYUN_COM_GPU_MEM_POD和ALIYUN_COM_GPU_MEM_ASSUME_TIME保存至Pod的annotation中,并且在此时进行Pod和所选节点的绑定。注意:这时还会保存ALIYUN_COM_GPU_MEM_ASSIGNED的Pod annotation,它被初始化为“false”。它表示该Pod在调度时刻被指定到了某块GPU卡,但是并没有真正在节点上创建该Pod。ALIYUN_COM_GPU_MEM_ASSUME_TIME代表了指定时间。如果此时发现分配节点上没有GPU资源符合条件,此时不进行绑定,直接不报错退出,默认调度器会在assume超时后重新调度。调用Kubernetes API执行节点和Pod的绑定以下图为例,当GPU Share Scheduler Extender要把gpu-mem:8138的Pod和经过筛选出来的节点N1绑定,首先会比较不同GPU的可用资源,分别为GPU0(12207),GPU1(8138),GPU2(4069),GPU3(16276),其中GPU2所剩资源不满足需求,被舍弃掉;而另外三个满足条件的GPU中, GPU1恰恰是符合空闲资源满足条件但同时又是所剩资源最少的GPU卡,因此GPU1被选出。3. 节点上运行当Pod和节点绑定的事件被Kubelet接收到后,Kubelet就会在节点上创建真正的Pod实体,在这个过程中, Kubelet会调用GPU Share Device Plugin的Allocate方法, Allocate方法的参数是Pod申请的gpu-mem。而在Allocate方法中,会根据GPU Share Scheduler Extender的调度决策运行对应的Pod3.1 会列出该节点中所有状态为Pending并且ALIYUN_COM_GPU_MEM_ASSIGNED为false的GPU Share Pod3.2 选择出其中Pod Annotation的ALIYUN_COM_GPU_MEM_POD的数量与Allocate申请数量一致的Pod。如果有多个符合这种条件的Pod,就会选择其中ALIYUN_COM_GPU_MEM_ASSUME_TIME最早的Pod。3.3 将该Pod的annotation ALIYUN_COM_GPU_MEM_ASSIGNED设置为true,并且将Pod annotation中的GPU信息转化为环境变量返回给Kubelet用以真正的创建Pod。相关项目目前项目已经开源到github.com上gpushare-scheduler-extendergpushare-device-plugin部署请参照部署文档测试样例1. 首先创建一个使用aliyun.com/gpu-mem的应用apiVersion: apps/v1kind: Deploymentmetadata: name: binpack-1 labels: app: binpack-1spec: replicas: 1 selector: # define how the deployment finds the pods it manages matchLabels: app: binpack-1 template: # define the pods specifications metadata: labels: app: binpack-1 spec: containers: - name: binpack-1 image: cheyang/gpu-player:v2 resources: limits: # MiB aliyun.com/gpu-mem: 1024使用请参照使用文档构建请参照如何构建视频DemoDemo 1: 部署多个GPU Share的Pod,发现他们以binpack的方式被放置到同一个GPU卡上视频地址:http://cloud.video.taobao.com…Demo 2:避免错误调度申请资源超过单个GPU可用资源的Pod视频地址:http://cloud.video.taobao.com…Roadmap利用nvidia MPS实现隔离支持该方案可以在由kubeadm初始化的Kubernetes集群自动化部署Scheduler Extener的高可用性为GPU, RDMA 和弹性网卡提供通用方案本文作者:必嘫阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

February 19, 2019 · 1 min · jiezi

github Repository not found 解决办法

git pull的时候遇到下面的报错。remote: Repository not foundfatal: repository ‘https://github.com/MyRepo/project.git/' not found解决办法如下,然后再执行git pull就会让你输入账号密码。就可以正常使用啦。$ git credential-manager uninstall$ git credential-manager install

February 18, 2019 · 1 min · jiezi

SpringBoot 实战 | 用 JdbcTemplates 访问 Mysql

微信公众号:一个优秀的废人如有问题或建议,请后台留言,我会尽力解决你的问题。前言如题,今天介绍 springboot 通过jdbc访问关系型mysql,通过 spring 的 JdbcTemplate 去访问。准备工作SpringBoot 2.xjdk 1.8maven 3.0ideamysql构建 SpringBoot 项目,不会的朋友参考旧文章:如何使用 IDEA 构建 Spring Boot 工程项目目录结构pom 文件引入依赖<dependencies>xml <!– jdbcTemplate 依赖 –> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!– 开启web: –> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!– mysql连接类 –> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!– https://mvnrepository.com/artifact/com.alibaba/druid –> <!– druid 连接池–> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.13</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies>application.yaml 配置数据库信息spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=true username: 数据库用户名 password: 数据库密码实体类package com.nasus.domain;/** * Project Name:jdbctemplate_demo <br/> * Package Name:com.nasus.domain <br/> * Date:2019/2/3 10:55 <br/> * <b>Description:</b> TODO: 描述该类的作用 <br/> * * @author <a href=“turodog@foxmail.com”>nasus</a><br/> * Copyright Notice ========================================================= * This file contains proprietary information of Eastcom Technologies Co. Ltd. * Copying or reproduction without prior written approval is prohibited. * Copyright (c) 2019 ======================================================= /public class Student { private Integer id; private String name; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return “Student{” + “id=” + id + “, name=’” + name + ‘'’ + “, age=” + age + ‘}’; }}dao 层package com.nasus.dao;import com.nasus.domain.Student;import java.util.List;/* * Project Name:jdbctemplate_demo <br/> * Package Name:com.nasus.dao <br/> * Date:2019/2/3 10:59 <br/> * <b>Description:</b> TODO: 描述该类的作用 <br/> * @author <a href=“turodog@foxmail.com”>nasus</a><br/> /public interface IStudentDao { int add(Student student); int update(Student student); int delete(int id); Student findStudentById(int id); List<Student> findStudentList();}具体实现类:package com.nasus.dao.impl;import com.nasus.dao.IStudentDao;import com.nasus.domain.Student;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.BeanPropertyRowMapper;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Repository;/* * Project Name:jdbctemplate_demo <br/> * Package Name:com.nasus.dao.impl <br/> * Date:2019/2/3 11:00 <br/> * <b>Description:</b> TODO: 描述该类的作用 <br/> * * @author <a href=“turodog@foxmail.com”>nasus</a><br/> /@Repositorypublic class IStudentDaoImpl implements IStudentDao{ @Autowired private JdbcTemplate jdbcTemplate; @Override public int add(Student student) { return jdbcTemplate.update(“insert into student(name, age) values(?, ?)”, student.getName(),student.getAge()); } @Override public int update(Student student) { return jdbcTemplate.update(“UPDATE student SET NAME=? ,age=? WHERE id=?”, student.getName(),student.getAge(),student.getId()); } @Override public int delete(int id) { return jdbcTemplate.update(“DELETE from TABLE student where id=?",id); } @Override public Student findStudentById(int id) { // BeanPropertyRowMapper 使获取的 List 结果列表的数据库字段和实体类自动对应 List<Student> list = jdbcTemplate.query(“select * from student where id = ?”, new Object[]{id}, new BeanPropertyRowMapper(Student.class)); if(list!=null && list.size()>0){ Student student = list.get(0); return student; }else{ return null; } } @Override public List<Student> findStudentList() { // 使用Spring的JdbcTemplate查询数据库,获取List结果列表,数据库表字段和实体类自动对应,可以使用BeanPropertyRowMapper List<Student> list = jdbcTemplate.query(“select * from student”, new Object[]{}, new BeanPropertyRowMapper(Student.class)); if(list!=null && list.size()>0){ return list; }else{ return null; } }}service 层package com.nasus.service;import com.nasus.domain.Student;import java.util.List;/* * Project Name:jdbctemplate_demo <br/> * Package Name:com.nasus.service <br/> * Date:2019/2/3 11:17 <br/> * <b>Description:</b> TODO: 描述该类的作用 <br/> * * @author <a href=“turodog@foxmail.com”>nasus</a><br/> /public interface IStudentService { int add(Student student); int update(Student student); int delete(int id); Student findStudentById(int id); List<Student> findStudentList();}实现类:package com.nasus.service.impl;import com.nasus.dao.IStudentDao;import com.nasus.domain.Student;import com.nasus.service.IStudentService;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Repository;/* * Project Name:jdbctemplate_demo <br/> * Package Name:com.nasus.service.impl <br/> * Date:2019/2/3 11:18 <br/> * <b>Description:</b> TODO: 描述该类的作用 <br/> * * @author <a href=“turodog@foxmail.com”>nasus</a><br/> * Copyright Notice ========================================================= * This file contains proprietary information of Eastcom Technologies Co. Ltd. * Copying or reproduction without prior written approval is prohibited. * Copyright (c) 2019 ======================================================= /@Repositorypublic class IStudentServiceImpl implements IStudentService { @Autowired private IStudentDao iStudentDao; @Override public int add(Student student) { return iStudentDao.add(student); } @Override public int update(Student student) { return iStudentDao.update(student); } @Override public int delete(int id) { return iStudentDao.delete(id); } @Override public Student findStudentById(int id) { return iStudentDao.findStudentById(id); } @Override public List<Student> findStudentList() { return iStudentDao.findStudentList(); }}controller 构建 restful apipackage com.nasus.controller;import com.nasus.domain.Student;import com.nasus.service.IStudentService;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.DeleteMapping;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.PutMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/* * Project Name:jdbctemplate_demo <br/> * Package Name:com.nasus.controller <br/> * Date:2019/2/3 11:21 <br/> * <b>Description:</b> TODO: 描述该类的作用 <br/> * * @author <a href=“turodog@foxmail.com”>nasus</a><br/> */@RestController@RequestMapping("/student”)public class StudentController { @Autowired private IStudentService iStudentService; @PostMapping("") public int addStudent(@RequestBody Student student){ return iStudentService.add(student); } @PutMapping("/{id}") public String updateStudent(@PathVariable Integer id, @RequestBody Student student){ Student oldStudent = new Student(); oldStudent.setId(id); oldStudent.setName(student.getName()); oldStudent.setAge(student.getAge()); int t = iStudentService.update(oldStudent); if (t == 1){ return student.toString(); }else { return “更新学生信息错误”; } } @GetMapping("/{id}") public Student findStudentById(@PathVariable Integer id){ return iStudentService.findStudentById(id); } @GetMapping("/list") public List<Student> findStudentList(){ return iStudentService.findStudentList(); } @DeleteMapping("/{id}") public int deleteStudentById(@PathVariable Integer id){ return iStudentService.delete(id); }}演示结果其他的 api 测试可以通过 postman 测试。我这里已经全部测试通过,请放心使用。源码下载:https://github.com/turoDog/De…后语以上SpringBoot 用 JdbcTemplates 访问Mysql 的教程。最后,对 Python 、Java 感兴趣请长按二维码关注一波,我会努力带给你们价值,如果觉得本文对你哪怕有一丁点帮助,请帮忙点好看,让更多人知道。另外,关注之后在发送 1024 可领取免费学习资料。资料内容详情请看这篇旧文:Python、C++、Java、Linux、Go、前端、算法资料分享 ...

February 17, 2019 · 4 min · jiezi

使用Heroku,解决gitment登录失败,报[object ProgressEvent]的错

前情提要本文详细记录了使用Heroku,解决gitment登录失败,报[object ProgressEvent]的问题。某种程度上借助了网友的思路和方法,并使用了免费的强大的Heroku。某些步骤可能需要梯子。(废话少说直接开干) gitment登录失败,报[object ProgressEvent],原作者的服务无法访问。然后去GitHub的issue找解决办法,发现一群网友也遇到了同样的问题。有大佬说直接使用github认证的接口// 将 gitment.js中的 _utils.http.post(‘https://gh-oauth.imsun.net’, {})// 改为_utils.http.post(‘https://github.com/login/oauth/access_token', {})如果你的网站使用的是GitHub Page,并且使用GitHub提供的域名,如“https://yiluyanxia.github.io/…”, 那么你只需要做到这一步就可以重新正常使用gitment,但是你和我一样作,偏要没事捣鼓一个自己的域名,那你就要往下看了。 从自己的域名直接访问github认证的接口,这样就跨域了。原作者应该也是考虑到这点,才会自己搭建一个访问github认证的node服务。废话少说直接开干Heroku是一个支持多种编程语言的云平台即服务,注册Heroku,在右上角的“new”,选择“Create New App”新建一个应用。根据操作系统下载并安装Heroku CLI,或者使用npm install heroku。 npm install heroku登陆heroku,OS X输入指令之后,会自动打开一个页面,而Windows要手动输入账号密码。(不知道亲们是不是也是一样) heroku login2和3的详细介绍可以看这里–>开始你的node服务详细步骤获取gh-oauth-server git clone https://github.com/imsun/gh-oauth-server.git修改package.json,在script中添加如下代码 “heroku”: “NODE_ENV=production node server"新建Procfile文件,输入以下内容 web: npm run heroku在heroku上找到你刚刚创建的应用,切换到“Deploy”,有详细的操作步骤,$ heroku git:clone -a YourAppName$ cd YourAppName$ git add .$ git commit -am “make it better”$ git push heroku master切换到“Settings”,找到“Domain”的值,即应用的地址。// 将 gitment.js中的 _utils.http.post(‘https://gh-oauth.imsun.net’, {})// 改为_utils.http.post(‘https://YourAppName.herokuapp.com/', {})至此,所有的步骤走完,你就可以愉快的使用gitment了。当然,如果你有自己的服务器,发布到上面是最好的。但本渣没有这个能力!!!

February 17, 2019 · 1 min · jiezi

[译]PEP 380--子生成器的语法

导语: PEP(Python增强提案)几乎是 Python 社区中最重要的文档,它们提供了公告信息、指导流程、新功能的设计及使用说明等内容。对于学习者来说,PEP 是非常值得一读的第一手材料,学习中遇到的大部分难题,都能在 PEP 中找到答案或者解决思路。我翻译了几篇 PEP,这么做的目的一方面是为了加强学习,另一方面也是为了锻炼自己的英文水平。Python 与 English,都是如此重要。翻译能将两者巧妙地结合起来,真是一举两得。本文介绍了子生成器的语法,即 yield from 语法。其它与生成器相关的 PEP 有 3 篇,翻译的结果附在了本文末尾。若有对翻译感兴趣的同学,可在 Github 上关注下我创建的项目 peps-cn 。PEP原文 : https://www.python.org/dev/pe...PEP标题: Syntax for Delegating to a SubgeneratorPEP作者: Gregory Ewing创建日期: 2009-02-13合入版本: 3.3译者 :豌豆花下猫(Python猫 公众号作者)目录摘要PEP接受动机提议StopIteration 的增强形式语义基本原理重构原则结束方式作为线程的生成器语法优化使用StopIteration来返回值被拒绝的建议批评可选的提案附加材料参考资料版权摘要为生成器提出了一种新的语法,用于将部分的操作委派给其它的生成器。这使得一部分包含“yield”的代码段,可以被分离并放置到其它生成器中。与此同时,子生成器会返回一个值,交给委派生成器(delegating generator)使用。当一个生成器再次 yield 被另一个生成器生成的值时,该语法还创造了一些优化的可能。PEP接受Guido 于 2011 年 6 月 26 日正式接受本 PEP。动机Python 的生成器是一种协程,但有一个限制,它只能返回值给直接的调用者。这意味着包含了 yield 的代码段不能像其它代码段一样,被拆分并放入到单独的函数中。如果做了这样的分解,就会导致被调用的函数本身成为一个生成器,并且必须显式地迭代这个生成器,以便重新 yield 它产生的所有值。如果只关心生成值的过程,那么可以不费劲地使用如下的循环:for v in g: yield v但是,如果在调用send(),throw()和close()的情况下,要使子生成器与调用者正确地交互,就相当困难。如后面所说,必要的代码非常复杂,因此想要正确地处理所有特殊情况,将会非常棘手。一种新的语法被提出来解决此问题。在最简单的用例中,它等同于上面的 for-循环,并且可以处理生成器的所有的行为,同时还能用简单而直接的方式进行重构。提议以下的新的生成器语法将被允许在生成器的内部使用:yield from <expr>其中 <expr> 表达式作用于可迭代对象,从迭代器中提取元素。该迭代器会遍历到耗尽,在此期间,它直接向包含 yield from 表达式的调用者生成器(即“委托生成器”)生成和接收值。此外,当该迭代器是一个生成器时,则此生成器可以执行 return 语句返回一个值,而该值将成为 yield from 表达式的值。yield from 表达式的完整语义可通过生成器协议来描述如下:迭代器返回的任何值都直接传给调用者。使用 send() 发送给委托生成器的任何值都直接传给迭代器。如果发送的值是 None,则调用迭代器的 next() 方法。如果发送的值不是 None,则调用迭代器的 send() 方法。如果调用引发了 StopIteration,则恢复委托生成器。任何其它异常都会传递给委托生成器。除 GeneratorExit 以外,任何传给委托生成器的异常都会传给迭代器的 throw() 方法。如果调用引发 StopIteration,则恢复委托生成器。任何其它异常都会传递给委托生成器。如果传给委托生成器的是 GeneratorExit 异常,或者调用委托生成器的 close() 方法,则迭代器的 close() 方法会被调用(如果有)。如果调用时出现异常,则会传给委托生成器。否则的话,在委托生成器中抛出 GeneratorExit。yield from 表达式的值是迭代器终止时引发的 StopIteration 异常的第一个参数。生成器里的 return expr 导致从生成器退出时引发 StopIteration(expr)。StopIteration的增强功能为方便起见,StopIteration 异常被赋予了一个 value 属性,来保存它的第一个参数,若无参数,则为 None。正式的语义本节使用 Python 3语法。1、RESULT = yield from EXPR 语句等同于以下语句:_i = iter(EXPR)try: _y = next(_i)except StopIteration as _e: _r = _e.valueelse: while 1: try: _s = yield _y except GeneratorExit as _e: try: _m = _i.close except AttributeError: pass else: _m() raise _e except BaseException as _e: _x = sys.exc_info() try: _m = _i.throw except AttributeError: raise _e else: try: _y = _m(*_x) except StopIteration as _e: _r = _e.value break else: try: if _s is None: _y = next(_i) else: _y = _i.send(_s) except StopIteration as _e: _r = _e.value breakRESULT = _r2、在生成器中,return value 语句在语义上等同于 raise StopIteration(value) ,除了一点,当前返回的生成器中的 except 子句无法捕获该异常。3、 StopIteration 异常的行为就像这样定义:class StopIteration(Exception): def init(self, *args): if len(args) > 0: self.value = args[0] else: self.value = None Exception.init(self, *args)基本原理重构原则上面提到的大多数语义,其背后的基本原理源于一种对生成器代码进行重构的愿望。即希望可以将包含一个或多个 yield 表达式的代码段,分离进一个单独的函数中(使用常规手段来处理作用域范围内的变量引用,等等),并通过 yield from 表达式来调用该函数。在合理可行的情况下,这种复合而成的生成器的行为应该跟原始的非分离的生成器完全相同,包括调用 __next () 、send()、throw() 和 close() 。子迭代器(而非生成器)的语义被选择成为生成器案例的合理泛化(generalization)。所提出的语义在重构方面具有如下限制:一个捕获了 GenetatorExit 却不重新抛出的代码块,不能在完全保留相同行为的情况下被分离出去。如果将 StopIteration 异常抛进了委托生成器中,则分离的生成器的行为跟原始代码的行为可能会不同。由于这些用例几乎不存在,因此不值得为支持它们而考虑额外的复杂性。结束方式当在 yield from 处挂起时,并且使用 close() 方法显式地终止委托生成器时,关于是否要一并终止子迭代器,存在一些争议。一个反对的论据是,如果在别处存在对子迭代器的引用,这样做会导致过早结束它。对非引用计数型的 Python 实现的考虑,导致了应该显式地结束的结论,以便在所有类型的 Python 实现上,显式地结束子迭代器与非重构的迭代器,能具有相同的效果。这里做的假设是,在大多数用例中,子迭代器不会被共享。在子迭代器被共享的稀有情况下,可通过一个阻塞调用 throw() 和 close() 的装饰器来实现,或者使用除 yield from 以外的方法来调用子迭代器。作为线程的生成器使生成器能够 return 值的动机,还考虑到使用生成器来实现轻量级的线程。当以这种方式使用生成器时,将轻量级线程的计算扩散到许多函数上就会是合理的。人们希望能够像调用普通函数一样调用子生成器,传递给它参数并接收返回值。使用提议的语法,像以下的表达式y = f(x)其中 f 是一个普通的函数,就可以被转化成一个委托调用y = yield from g(x)其中 g 是生成器。通过把 g 想象成一个普通的能被 yield 语句挂起的函数,人们可以推断出结果代码的行为。当以这种方式把生成器作为线程使用时,通常人们不会对 yield 所传入或传出的值感兴趣。但是,也有一些例子,线程可以作为 item 的生产者或消费者。yield from 表达式允许线程的逻辑被扩散到所需的尽可能多的函数中,item 的生产与消费发生在任意的子函数中,并且这些 item 会自动路由到/去它们的最终来源/目的地。对于 throw() 与 close() ,可以合理地预期,如果从外部向线程内抛入了一个异常,那么首先应该在线程挂起处的最内部的生成器中引发,再从那里向外传递;而如果线程是从外部调用 close() 来终结的,那也应该从最内部往外地终止处于活动态的生成器链。语法所提出的特定语法被选中,像它的含义所暗示,并没有引入任何新的关键词,且清晰地突出了它与普通 yield 的不同。优化当存在一长串生成器时,使用专门的语法就为优化提供了可能性。这种生成器链可能存在,例如,当递归遍历树结构时。在链上传递 next() 的调用与 yield 返回值,可能造成 O(n) 开销,最坏情况下会是 O(n**2)。可能的策略是向生成器对象添加一个槽(slot)来保存委派给它的生成器。当在生成器上调用 next() 或 send() 时,首先检查该槽,如果非空,则它引用的生成器将会被激活。如果引发了 StopIteration,该槽会被清空,并且主生成器会被激活。这将减少一系列 C 函数调用的委托开销,并不涉及 Python 代码的执行。一种可能的增强方法是在循环中遍历整个生成器链,并直接激活最后一个生成器,尽管 StopIteration 的处理会比较复杂。使用StopIteration来返回值有多种方法可以将生成器的返回值传回。也有一些替代的方法,例如将其存储为生成器-迭代器对象的属性,或将其作为子生成器的 close() 方法的调用值返回。然而,本 PEP 提议的机制很有吸引力,有如下理由:使用泛化的 StopIteration 异常,可以使其它类型的迭代器轻松地加入协议,而不必增加额外的属性或 close() 方法。它简化了实现,因为子生成器的返回值变得可用的点与引发异常的点相同。延迟到任意时间都需要在某处存储返回值。被拒绝的建议一些想法被讨论并且拒绝了。建议:应该有一些方法可以避免对__next() 的调用,或者用带有指定值的 send() 调用来替换它,目的是支持对生成器作装饰,以便可以自动地执行初始的 next() 。决议:超出本提案的范围。这种生成器不该与 yield from 一起使用。建议:如果关闭一个子迭代器时,引发了带返回值的 StopIteration 异常,则将该值从 close() 调用中返回给委托生成器。此功能的动机是为了通过关闭生成器,传信号给传入生成器的最后的值。被关闭的生成器会捕获 GeneratorExit ,完成其计算并返回一个结果,该结果最终成为 close() 调用的返回值。决议:close() 与 GeneratorExit 的这种用法,将与当前的退出(bail-out)与清理机制的角色不兼容。这要求在关闭子生成器后、关闭一个委托生成器时,该委托生成器可以被恢复,而不是重新引发 GeneratorExit。但这是不可接受的,因为调用 close() 进行清理的意图,无法保证委托生成器能正确地终止。通过其它方式,可以更好地处理向消费者告知(signal)最后的值的问题,例如发送一个哨兵值(sentinel value)或者抛入一个被生产者与消费者都认可的异常。然后,消费者可以检查该哨兵或异常,通过完成其计算并正常地返回,来作响应。这种方案在存在委托的情况下表现正确。建议:如果 close() 不返回值,如果出现 StopIteration 中带有非 None 的值,则抛出一个异常。决议:没有明确的理由如此做。忽略返回值在 Python 中的任何其它地方,都不会被视为错误。批评根据本提案,yield from 表达式的值将以跟普通 yield 表达式非常不同的方式得出。这意味着其它不包含 yield 表达式的语法可能会更合适,但到目前为止,还没有提出可接受的替代方案。被拒绝的替代品包括 call、delegate 和 gcall。有人提议,应该使用子生成器中除 return 以外的某些机制,来处理 yield from 表达式的返回值。但是,这会干扰将子生成器视为可挂起函数的目的,因为它不能像其它函数一样 return 值。有人批评,说使用异常来传递返回值是“滥用异常”,却没有任何具体的理由来证明它。无论如何,这只是一种实现的建议;其它机制可以在不丢失本提案的任何关键特性的情况下使用。有人建议,使用与 StopIteration 不同的异常来返回值,例如 GeneratorReturn。但是,还没有令人信服的实际理由被提出,并且向 StopIteration 添加 value 属性减轻了从异常(该异常可能存在也可能不存在)中提取返回值的所有困难。此外,使用不同的异常意味着,与普通函数不同,生成器中不带值的 return,将不等同于 return None 。可选的提案之前已经提到了类似的提议,有些语法使用 yield 而不是 yield from。虽然 yield 更简洁,但是有争议的是,它看起来与普通的 yield 太相似了,可能在阅读代码时会忽视了其中的差异。据作者所知,之前的提案只关注于 yield 产生值,因此遭受到了批评,即他们所替代的两行 for 循环并没有足够令人厌烦,不足以让人为新的语法辩护。通过处理完整的生成器协议,本提案提供了更多的好处。附加材料本提案的语法的一些用例已经被提供出来,并且基于上面概括的第一个优化的原型也已实现。Examples and Implementation可以从跟踪器问题的 issue 11682 中获得针对 Python 3.3 实现的升级版本。参考资料[1] https://mail.python.org/pipermail/python-dev/2011-June/112010.html [2] http://www.cosc.canterbury.ac.nz/greg.ewing/python/yield-from/ [3] http://bugs.python.org/issue11682版权本文档已经放置在公共领域。源文档:https://github.com/python/pep…————-(译文完)————-相关链接: PEP背景知识 :学习Python,怎能不懂点PEP呢?PEP翻译计划 :https://github.com/chinesehua…[[译] PEP 255–简单的生成器](https://mp.weixin.qq.com/s/vj...[[译] PEP 342–增强型生成器:协程](https://mp.weixin.qq.com/s/M7...[[译] PEP 525–异步生成器](https://mp.weixin.qq.com/s/fy…公众号【Python猫】, 专注Python技术、数据科学和深度学习,力图创造一个有趣又有用的学习分享平台。本号连载优质的系列文章,有喵星哲学猫系列、Python进阶系列、好书推荐系列、优质英文推荐与翻译等等,欢迎关注哦。PS:后台回复“爱学习”,免费获得一份学习大礼包。 ...

February 16, 2019 · 2 min · jiezi

消除GitHub上的历史记录

GitHub作为全球最大的交友平台而被我们所熟知,但是我们有时候会将某些不适当的信息发布到网络上去,而GitHub并没有良好的交互界面让我们能在两分钟内撤回错误。作为世界上比较有名的犬种,在将个人的某些账号信息以及某些资源(捂脸)完全公开之后,内心没有丝毫波动,甚至有点想笑,我为什么会出现这种破问题。本着万事开头难,中间难,结尾难的想法,在被世人所不齿之前,踏上自救之路。方案一:删库方案二:三个步骤,其实前两步都没什么用首先将当前版本的某些数据删掉(做完这一步之后突然意识到我可能连有名的犬种都不算);其次将仓库设为私有(此时已经能免费设置私有仓库了,先谢谢一下微软),打开GitHub Help(GitHub对我这种曾经没用功读书的人非常不友好,学霸读到这就可以跳过阅读原文),输入 removing sensitive 的时候,出现了几个提示引起我的注意:删除敏感数据;敏感数据删除策略;移除文件历史;最后删除敏感数据,文章大概意思如下:清除仓库中的敏感数据如果你提交了敏感数据,例如密码或者SSH秘钥之类的到Git仓库, 你可以从历史中删掉他们。想完全删除不想要的文件历史记录你可以使用 git filter-branch 命令或者 BFG Repo-Cleaner 开源社区工具。git filter-branch 命令和 BFG Repo-Cleaner 可以重写你的仓库历史,他们可以更改目前存在的任何单独提交记录的或者有依赖的提交记录(SHA意思为哈希算法,可理解为提交记录)。修改提交记录可能会影响正在使用的 pull request,我们建议在进行清除敏感数据之前进行必要的合并或关闭请求。你也可以使用 git rm 命令来删除文件。关于删除最新提交文件的信息可移步“Removing files from a repository’s history”。警告:一旦你提交到GitHub,应该考虑到数据可能会受到的任何影响。如果提交了密码,修改密码,提交了秘钥,及时换一个新的。本文将阐述……(到这已经记不清英语老师长什么样了)清除仓库的文件历史记录使用 BFGBFG Repo-Cleaner 是一个由开源社区开发且维护的工具,它提供了比git filter-branch更加简便快捷的方法来删除不想要的数据。比如,删除你文件中的敏感数据且不影响最新的提交,执行:$ bfg –delete-files YOUR-FILE-WITH-SENSITIVE-DATA可以在password.txt中列出所有文本来进行替换,执行:$ bfg –replace-text passwords.txt具体使用文档和下载说明请移步 https://rtyley.github.io/bfg-…读到这发现正文终于要开始了,但GitHub提供的信息仍旧是看不懂,好在BFG托管在GitHub上,在官网上下载bfg.jar,安装Java环境,好在Java环境的安装非常简单,我就不在此说明了。我们接下来开始删除数据首先克隆你的项目,并使用–mirror:$ git clone –mirror git://example.com/repo.git克隆完后接着就可以执行之前下载的bfg.jar,将jar放到克隆项目后的文件夹内,和repo.git(此处项目名会不同)同级,YOUR-FILE-WITH-SENSITIVE-DATA是你包含敏感信息的文件名,不用写明路径:java -jar bfg.jar –delete-files YOUR-FILE-WITH-SENSITIVE-DATA repo.git执行结束后会出现如下结果进入到repo.git下,我们还需执行git gc命令:cd repo.git$ git reflog expire –expire=now –all && git gc –prune=now –aggressive最后,我们将修改结果提交:$ git push理论上到这已经是清除掉记录了,我的提交记录确实变了,但是还是能找到某些羞羞的数据,因为之前在第一步的时候将这个文件给删掉了,于是又把文件提交到仓库,然后在执行上述步骤,终于危机解除,英雄又一次拯救了世界,散花之前注意到还有执行完jar之后最后有三行文字,让我在复现一下。最后撒花。使用 filter-branch由于使用filter-branch还需要提交删除请求,毕竟要解释删除的数据是干嘛的(捂脸),况且BFG自称速度是filter-branch的10~720倍。感兴趣的同学可以了解一下。以下是数据移除策略的部分内容,官方列举了什么是敏感数据以及一些注意事项,以及解释了GitHub如何移除这些数据,还有如何发送移除数据请求以及请求内容应包含事项(下图)等。图中的大概意思是:发送一份删除敏感数据的请求由于连接GitHub主机的内容以及管理方式的不同,我们需要你提供的信息越具体越好,为了确保我们核实用户并能够彻底移除敏感数据,我们需要知道从哪开始。以下几点简单说明了移除敏感数据的步骤。你的请求内容应该有:每一个包含敏感数据的文件都有一个能正常指向该文件的链接。(注意,GitHub不能通过搜索结果,示例以及截屏来处理你的请求)详细说明你的每个文件中敏感数据所在的行数。简要描述敏感信息可能带来的风险,并且着重说明它是如何产生安全风险的。如果你是第三方或者其他代理机构所面临安全风险,请提供合法的授权表明你有执行权利。可选项:让GitHub知道在删除数据请求前所面临的紧急情况和原因,我们会尽快处理你的删除请求;如果你的请求对时间敏感性有特殊的要求,例如公开最近的凭证等,请做出解释。如何提交请求你可以将删除请求发送到 support@github.com 或者通过GitHub的 Contact form 提交,请在邮件正文中包含一份纯文本格式的请求,邮件携带附件的话可能会存在处理延迟。如需转载,请注明文章出处:https://segmentfault.com/a/11…原创不易,感谢支持。

February 15, 2019 · 1 min · jiezi