软考改革成无纸化考试已经实锤。根据陕西软考办官网的消息,从2023年11月起,软考的所有科目都将改为机器考试形式。详情请参阅:
那么软考考试改为机考后,对我们会有哪些影响呢?我来简单概括一下。
1、复习的方法可以根据自己的情况来选择和调整,但学习的知识点还是一样的,甚至可能会更多。因此,我们必须认真地进行复习。
2、如果你打字速度较慢,必要要有意识地练习打字了。
3、就像先前的文件中所提到的:
考试可能会进行分批次,具体的题目出题方式、试卷数量、考试题型以及时间等方面是否有变化,我们现在不需要过多纠结,等待后续通知即可。与其过多纠结这些问题,不如多学习一些考点知识。
4、机考支持哪些输入法?以注会考试为例,机考支持以下5种输入法:微软拼音输入法、谷歌拼音输入法、搜狗拼音输入法、极品五笔输入法和万能五笔输入法。
5、在机考中是否一定无需绘图?实际上这并非确定的事情,因为考试系统可能会自带一些绘图工具和计算器功能。
6、论文是否能够进行查重是可能的吗?论文查重的技术问题并不大,我建议我们应该做好查重的准备。备考的方法又是怎样呢?我建议大家最好写自己原创的论文,或者在参考范文之后尽可能地进行修改。
在平时的准备中,一定要对范文中的背景、过渡和结尾进行一些修改。
在考试的时候,要根据每个子题目进行修改和完善,更加突出每个子题目的重点。总体来说,尽量多展现自己的语言能力。
当然,这只是我猜的,要不要检查重复?质量控制的标准是什么?目前还不清楚。
7、在考试时不必携带文具。
8、对那些书写速度慢、字迹不好、纸面不整洁、需要涂改、经常忘字的朋友而言,这是一个好消息。
9、考完后立即出分,这种情况可能性不大。
10、无论考试形式如何,核心内容都是一样的。以中级系统集成项目管理工程师为例,全国卷和广东卷都有出现过。其上午的核心考点是相同的,下午的案例可能会涉及不同的领域。这就意味着对我们的预测造成了影响:核心考点一样,案例和论文的预测可能会更加困难。
使用相同图集资源:确保一个 Prefab 中的所有资源来自同一个图集是一个良好的优化实践。这样做可以减少纹理切换和批次合并的开销,从而减少 DrawCall 的数量。在 Cocos Creator 中,使用 Label 并不会直接增加 DrawCall 的数量。Cocos Creator 使用了位图字体(Bitmap Font)来渲染 Label,这意味着文本的绘制通常会被合批处理,从而减少 DrawCall。避免随意改变纹理,纹理的改变通常会打断合批。谨慎使用默认精灵(default_sprite)、默认精灵闪屏(default_sprite-splash)和单色绘制:在 Cocos Creator 中,使用默认精灵和单色绘制并不会直接增加 DrawCall 的数量。这些功能通常会在引擎内部进行批次合并和优化,以减少 DrawCall。但是在某些情况下,例如在一个 Prefab 中使用了大量的默认精灵或单色绘制,可能会导致批次合并的失败,从而增加 DrawCall 的数量。因此,我们建议尽量避免在一个 Prefab 中使用大量的默认精灵和单色绘制。尽量减少透明度的使用:由于透明度需要进行混合计算,因此在有透明度的情况下很难进行批次合并,从而增加 DrawCall 的数量。因此,我们建议尽量避免在游戏中大量使用透明度。合理使用批次渲染功能:在 Cocos Creator 中,引擎提供了批次渲染(Batching)功能,可以将多个相同材质、相同渲染状态的渲染操作合并成一个批次,从而减少 DrawCall。因此,在开发过程中应该尽可能地使用批次渲染功能。减少节点数量:节点数量越多,渲染性能的消耗就越大。因此,在设计游戏场景和 UI 时,应该尽量减少节点数量,将多个相同的节点合并为一个节点,从而减少渲染性能的消耗。减少不必要的动态效果:动态效果通常需要消耗更多的 CPU 和 GPU 资源,因此在开发过程中应该尽量减少不必要的动态效果,或者尝试使用更高效的实现方式,例如在 UI 中使用静态图片代替动态效果。 综上所述,通过合理的优化和设计,可以有效地减少游戏的 DrawCall 数量,提高游戏的渲染性能。
前向渲染步骤: 延迟渲染步骤: 延迟渲染为啥不能处理透明物体
延迟渲染 (Deferred Rendering) 的主要特点是它首先将场景的几何信息和材料属性渲染到几个不同的纹理(称为G-buffer)中,然后在一个单独的步骤中计算最终的光照。这种方式允许它高效地处理场景中的大量光源。然而,这种方法在处理半透明物体时确实面临一些困难。
以下是为什么延迟渲染不适合直接处理半透明物体的原因:
G-buffer限制:延迟渲染需要将每个像素的材料属性存储在G-buffer中。这是基于每个像素的“最前面”的表面。半透明物体需要考虑多个表面的贡献,这使得在G-buffer中存储所有这些信息变得困难。
深度信息:G-buffer中的深度值通常仅存储最前面的表面深度。由于没有存储其他表面的深度信息,渲染半透明物体并考虑其与其他物体的混合关系变得困难。
混合问题:半透明物体需要进行混合运算来确定最终颜色。在延迟渲染的第一阶段(几何/材质阶段)中,我们并不真正计算最终的像素颜色,所以这一步无法处理混合。
性能考虑:即使在G-buffer中为半透明物体提供额外的存储空间,也会增加带宽和存储需求,从而可能导致性能下降。
尽管延迟渲染有这些局限性,但开发人员通常会结合使用前向渲染和延迟渲染来实现一个场景的渲染。这意味着他们可能会首先使用延迟渲染处理不透明的物体,然后使用前向渲染来处理半透明物体。这种方法结合了两种渲染技术的优势,允许场景中的不透明和半透明物体都被正确和高效地渲染。
现象 现在线上ES环境 性能查询较慢,并发增大,性能急剧下降
数据量大概 3000w条
20线程并发67s左右响应
50线程并发161s左右响应
部署版本 6.8.9
部署方式 docker
环境配置 CentOS7 2C 4G
JMETER 测试:
排查原因: 导入线上环境数据到本地,启动本地的ES服务,测试发现性能显著提高,
本地启动ES6.4.1服务(非docker),
以下几种可能导致线上服务性能:
1:数据源不同(线上的数据源包含一些冗余字段)
2:docker启动的ES镜像问题 (配置文件参数,启动参数,内存交换等)
3:内存限制问题(本地8G 线上4G)
4: ES版本的问题
问题排查过程: 1:数据源问题排查: 将本地环境数据导入线上,但是docker容器无法映射读取导入的数据源,镜像启动失败,停止使用docker容器,直接部署ES服务,映射测试环境数据源,无法启动ES,ES镜像映射的数据和ES直接部署的数据无法相互映射,无法排查
2:部署方式问题: 取消docker部署,按照正常流程部署ES服务,将本地环境数据导入线上环境,直接部署ES6.4.1,启动成功,性能提升
20线程并发响应时间提升到3s,50线程响应时间提升到9s,但是和本地的性能相比,仍有差距(本地2s和5s),线上和本地唯一区别就是内存的不同
线上加大内存8G,再次测试 ,性能和本地相近 ,目的达成
测试结果:
3: 版本问题 将本地的6.41更换线上6.8.9 测试发现性能接近
分析结果 1: 原因认定为docker容器启动 由于加了部分参数,或者配置文件的参数没有生效,在写入数据或者读取时候严重限制了检索性能。
ES直接部署无法正常读取docker部署映射的数据文件,两者部署方式产生的数据文件不一样
2:4G的服务器缓存上限2G,8G服务器上限5.8G 所以:8G比4G能支持更多的并发,当访问量过大时,可以更换8g的服务器,或者集群部署分发流量
背景 安装docker后,发现启动容器的端口8082 映射到宿主机的端口80访问主机没有反应,此时进入容器查看日志,发现并没有请求打进来
现象:
正在连接 localhost (localhost)|::1|:80… 已连接。
已发出 HTTP 请求,正在等待回应… 读取文件头错误 (Connection reset by peer)。
重试中。
排查 1:怀疑容器内的HTTP端口映射错了,进去其他容器,wget访问目标容器,发现可以访问,容器启动,映射没有问题
2:请求的端口到宿主机不通?防火墙端口未开放?IP白名单?
抓包看看:
可以抓到请求包,此路是通的
3:主机和容器不通?
宿主机ping docker容器,不通
结果宿主机无法ping通docker容器IP 这种情况一般是主机网络段地址和docker网段地址冲突导致的
修复方式
1:可以改用 host模式部署 --net=host
2:创建新网桥 指定其他网段 IP ,我这里将 172.28.0 更改为 172.19.0
docker network create --subnet=172.19.0.0/16 bridge2
浏览器渲染进程漏洞利用的一般思路是:在利用漏洞获得用户态任意地址读写权限后,通过篡改DOM、js等对象的虚表函数指针劫持程序执行流,通过ROP链调用VirtualProtect等Win32
API,修改保存shellcode
buffer的内存属性为PAGE_EXECUTE_READWRITE,最终由ROP链跳转到shellcode执行。Windows
8.1后,Microsoft引入了CFG(Control Flow
Guard)缓解技术[1],对间接调用的函数指针进行验证,从而缓解了通过篡改虚表函数指针劫持程序执行流这种利用技术。
然而对抗不会因此终止,随后出现了一些绕过CFG缓解技术的新方法,比如chakra/jscript9中通过篡改栈上函数返回地址劫持程序执行流[2],v8中利用具有可执行内存属性的WebAssembly对象执行shellcode[3]等。
2020年12月,Microsoft在Windows 10 20H1中基于Intel Tiger Lake
CPU加入了CET缓解技术[4],防护了通过篡改栈上函数返回地址劫持程序执行流的利用方法。因此,如何在有CET防护的环境中绕过CFG再次成为漏洞利用的难题。
在分析CVE-2021-26411在野利用样本时[5],我们发现了一种利用Windows RPC(Remote Procedure
Call)[5]绕过CFG的新方法,这种方法无需依赖ROP链,通过构造RPC_MESSAGE并调用rpcrt4!NdrServerCall2即可实现任意代码执行。
##** 1. CVE** ** -2021-26411** ** 回顾**
《IE浏览器在野0day:CVE-2021-26411分析》[5]
一文中介绍了该漏洞的根因:removeAttributeNode()触发属性对象nodeValue的valueOf回调,回调期间手动调用clearAttributes(),导致nodeValue保存的BSTR被提前释放。回调返回后,没有检查nodeValue是否存在继续使用该对象,最终导致UAF。
3月份Windows补丁中该漏洞的修复方法为,在CAttrArray::Destroy函数中删除对象操作前增加索引检查:
对于这样一个大小可控的UAF漏洞,利用思路为:利用两个不同类型的指针(BSTR和Dictionary.items)指向该空洞内存,通过类型混淆实现指针泄露和指针解引用:
##** 2. RPC原理** ** 及利用方法**
Windows RPC用来解决分布式客户端/服务端函数调用问题。基于RPC,客户端可以像调用本地函数一样调用服务端函数,RPC基本架构如下图:
客户端/服务端程序将调用参数/返回值等传给下层Stub函数,Stub函数负责封装数据成NDR(Network Data
Representation)格式,最后通过rpcrt4.dll提供的runtime库进行通信。
下面给出一示例idl:
当客户端调用add函数后,服务端由rpcrt4.dll接受处理请求并调用rpcrt4!NdrServerCall2:
rpcrt4!NdrServerCall2只有一个参数PRPC_MESSAGE,其中包含了客户端调用的函数索引、传参等重要数据,服务端RPC_MESSAGE结构及主要子数据结构如下图(32位):
如上图所示,RPC_MESSAGE结构中,函数调用关键的两个变量为Buffer和RpcInterfaceInformation。其中Buffer存放了函数的传参,RpcInterfaceInformation指向RPC_SERVER_INTERFACE结构。RPC_SERVER_INTERFACE结构保存了服务端程序接口信息,其中+0x2c
DispatchTable保存了runtime库和Stub函数的接口函数指针,+0x3c
InterpreterInfo指向MIDL_SERVER_INFO结构。MIDL_SERVER_INFO结构保存了服务端IDL接口信息,其中DispatchTable保存了服务端提供的远程调用例程的函数指针数组。
下面以一个实例介绍RPC_MESSAGE的结构:
根据上面给出的idl,当客户端调用add(0x111, 0x222),服务端程序断在rpcrt4!NdrServerCall2:
可以看到,动态调试的内存dump与RPC_MESSAGE结构分析一致,其中add函数就存放在MIDL_SERVER_INFO.
DispatchTable中。
接下来分析rpcrt4!NdrServerCall2是如何根据RPC_MESSAGE调用add函数的:
rpcrt4!NdrServerCall2内部调用rpcrt4!NdrStubCall2,rpcrt4!NdrStubCall2内部根据MIDL_SERVER_INFO.
DispatchTable的基地址和RPC_MESSAGE.
ProcNum计算调用的函数指针地址,将函数指针、函数参数和参数长度传给rpcrt4!Invoke:
rpcrt4!Invoke内部最终调用服务端例程函数:
通过上面的分析可以知道,在获得任意地址读写权限后,可以构造一个RPC_MESSAGE数据结构,传入想要调用的函数指针和函数参数,最后手动调用rpcrt4!NdrServerCall2,即可实现任意函数执行。
接下来需要解决两个问题:
1)如何通过js脚本调用rpcrt4! NdrServerCall2
2)观察rpcrt4!Invoke最后的服务端例程函数调用:
可以看到这里是一处间接调用,且有CFG检查。因此需要考虑替换MIDL_SERVER_INFO.
DispatchTable函数指针后如何绕过这里的CFG防护。
首先解决问题1: 如何通过js脚本调用rpcrt4! NdrServerCall2
这里可以复用替换DOM对象虚表函数指针劫持程序执行流的方法,因为rpcrt4!NdrServerCall2是记录在CFGBitmap里的合法指针,所以替换后依然可以通过CFG检查。样本里通过篡改MSHTML!CAttribute::normalize,最终由“xyz.normalize()”调用rpcrt4!NdrServerCall2。
接着解决问题2: 如何绕过rpcrt4!NdrServerCall2中的CFG防护
样本里的思路是:
利用伪造的RPC_MESSAGE和rpcrt4!NdrServerCall2调用VirtualProtect修改RPCRT4!__guard_check_icall_fptr内存属性为PAGE_EXECUTE_READWRITE
Gitee 产品配额说明
仓库容量 容量说明
社区版(个人用户)
类型 说明
仓库数量 创建 1000 个仓库,不限制公私有。
仓库容量 Git 单仓库容量上限为 500M ,SVN 单仓库容量上限为 400M
单文件最大 50M
用户总仓库容量为 5G
注:总仓库定义为用户名下以及所创建的组织下面的所有仓库。
附件容量 附件单文件大小上限为 100MB
单仓库附件总容量 1G
成员人数 公有仓库成员数量不限。
个人账号下所有私有仓库总的协作人数为 5人
企业版
套餐 免费版 基础版 标准版 高级版 尊享版
单仓库 最大 500 MB 最大 1 GB 最大 1 GB 最大 2 GB 最大 3 GB
单文件 最大 50 MB 最大 100 MB 最大 100 MB 最大 200 MB 最大 300 MB
目录
1. 前言
1.1 Minimax
1.2 剪枝
1.3 蒙特卡洛树搜索
1.4 为什么随机走子会可行呢?
2. vanilla Monte Carlo tree search 3. UCT-based trade-off between exploitation and exploration
4. MCTS基本算法流程
5. Efficiency Through Expert Policies
6. Efficiency Through Value Approximation
1. 前言 众所周知,像围棋、国际象棋等这一类两人对抗性游戏(discrete, deterministic games with perfect information)项目的智能agent或者说bot的实现的最关键算法之一是蒙特卡洛树搜索(Monte Carlo Tree Search)。
1.1 Minimax 在双人对弈游戏中,某一方下子时,会考虑所有可能落子,针对每一落子考虑对手所有可能的应手,针对对手的每种可能应手进一步考虑自己的应手,这样一直考虑下去,这个过程实际上就是在构建一棵搜索树进行搜索。。。理论上如果可能计算到终局(即构建完整的搜索树),就可以每一步都采取理论上最优的落子策略(不一定能够战无不胜,取决于游戏类型)。这个过程其实就是Minimax search algorithm(极小化极大搜索算法)的执行过程。
像Tic-tac-toe这样的小规模游戏,现代计算机可以轻松地从一开始就构建出所有可能棋盘局面构成的搜索树,从而可以给出理论最优解。因此基于minimax搜索算法可以很容易地设计出unbeatable tic-tac-toe agent/bot。之所以说是unbeatable而不是战无不胜的,是因为Tic-tac-toe游戏是一个有先手优势的游戏,假定先手方能下出最优解,后手方就不可能战胜先手方,最多只能下成平局。理想棋手与非理想棋手之间的对弈结果关系如下所示:
但是,对于像象棋(中国象棋、国际象棋、日本将棋等)或者围棋,分支系数太大,搜索树的规模呈指数方式快速增长,而且深度可能上百层(一局围棋的手数可以轻松到达2~300以上)。构建完整的搜索树是完全无法想象的,无论从存储资源还是从计算时间来说。
关于minimax,有兴趣者可以参考TicTacToe:Minimax-Agent以及人机对弈python实现
1.2 剪枝 解决以上搜索树规模爆炸问题的关键技术是剪枝,即通过忽略搜索树的某些部分来缩减搜索空间。
搜索树是2维的,它具有宽度和深度。
宽度是指某个特定棋局(注意,棋局有时是指一局棋,有时是指一个盘面状态,当前棋盘上的局面的意思。根据上下文应该可以好无歧义地判断是指那种意思)下可能动作的数据(常称分支系数,branching factor)。
深度是指从某个棋局开始到可能的棋局终局状态的手数(或者说回合数。但是通常来说两个各下一手称为一个回合)。
当然,这两个数值对于每一个棋局来说都可能是不同的。
剪枝可以从深度和宽度两个方面来考虑,相应地有两种典型的剪枝技术:
一是基于棋局评估函数来减少搜索深度;另一是用于减少搜索宽度的alpha-beta剪枝; 1.3 蒙特卡洛树搜索 剪枝(无论是深度还是宽度)技术的性能最终决定对棋局的评估,而对于围棋来说,棋局评估是一件非常困难的事情。蒙特卡洛树搜索(MCTS)为我们提供了一种有效的方法,不需要依赖于什么高深的游戏策略,也不需要利用游戏特定的启发式规则,通过模拟随机棋局的方式来进行棋局好坏的评估,并据此进行落子选择。
传参跳转 router-link的传参:query、params
<!-- father.vue --> <template> <div> <!-- 路由 --> <div> <!-- query方式 --> <router-link :to="{path:'/page1',query:{imgUrl}}">page1</router-link> <!-- params方式 --> <router-link :to="{name:'page2',params:{imgUrl}}">page2</router-link> </div> <router-view></router-view> </div> </template> 定义路由 import VueRouter from 'vue-router' import Vue from "vue" import FrameView from "./components/FrameView" import LoginView from "./components/LoginView" import LabelingView from "./components/LabelingView" import AlgoProcessView from "./components/AlgoProcessView" import MultiRouteView from "./components/MultiRouteView" // 嵌套路由 import Index from './components/index' import Merchant from './components/Merchant' Vue.use(VueRouter) const router = new VueRouter({ routes:[ { path:'/test', component:LabelingView, name:"
//**脚本作用:蚂蚁采集能量 //**脚本源码:金猪脚本 //**感兴趣的伙伴来学习交流吧:扣扣裙;741318378 auto.waitFor() if(!requestScreenCapture()) { alert("请求截图权限失败!"); exit(); } sleep(1200) /** * 可扩张弹框 */ // threads.start(function(){ // while(1){ // if(text('更新').exists()){ // click( // className('android.widget.Button').find()[1].bounds().centerX(), // className('android.widget.Button').find()[1].bounds().centerX() // ) // } // } // }) main() //#1DA06D 抓手颜色 function main(){ open_alipay() sleep(1500) if(open_Ant_forest()){ toastLog('自己的能量采集完成') sleep(1200) } Ant_forest_Friends() } /** * 打开支付宝 */ function open_alipay() { while(!text('扫一扫').exists() && !text('支付').exists()) { app.launch('com.eg.android.AlipayGphone'); sleep(2500) } toastLog('支付宝已经打开') return true } function open_Ant_forest() { if(text('蚂蚁森林').exists()) { if(!
目录 在何处执行?何时初始化?自己写一个ApplicationContextInitializer 那这个类的设计具体有什么作用呢??1. DelegatingApplicationContextInitializer2. SharedMetadataReaderFactoryContextInitializer3. ContextIdApplicationContextInitializer4. ConfigurationWarningsApplicationContextInitializer5. RSocketPortInfoApplicationContextInitializer6. ServerPoerInfoApplicationContextInitializer7. ConditionEvaluationReportLoggingListener 总结 在何处执行? 执行时机在SpringApplication类的prepareContenxt中,在run方法中可以找到prepareContext方法。
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { ... // 执行applyInitializers applyInitializers(context); ... } protected void applyInitializers(ConfigurableApplicationContext context) { for (ApplicationContextInitializer initializer : getInitializers()) { Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } } 何时初始化? 在SpringApplication构造函数中会初始化initializers。
@SuppressWarnings({ "unchecked", "rawtypes" }) public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { .
一、ApplicationContext在Spring Boot中是如何创建的? 1. SpringApplication ApplicationContextFactory有三个实现类,分别是AnnotationConfigReactiveWebServerApplicationContext.Factory、AnnotationConfigServletWebServerApplicationContext.Factory、DefaultApplicationContextFactory。
public ConfigurableApplicationContext run(String... args) { ... // 创建ApplicationContext context = createApplicationContext(); ... } // 调用DefaultApplicationContextFactory的create protected ConfigurableApplicationContext createApplicationContext() { return this.applicationContextFactory.create(this.webApplicationType); } 2. DefaultApplicationContextFactory 下面有一点代码SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class, getClass().getClassLoader()),是从org.springframework.boot的META-INF/spring.factories寻找ApplicationContextFactory的实现类,也就是AnnotationConfigReactiveWebServerApplicationContext.Factory和AnnotationConfigServletWebServerApplicationContext.Factory。
@Override public ConfigurableApplicationContext create(WebApplicationType webApplicationType) { try { return getFromSpringFactories(webApplicationType, ApplicationContextFactory::create, AnnotationConfigApplicationContext::new); } catch (Exception ex) { throw new IllegalStateException("Unable create a default ApplicationContext instance, " + "you may need a custom ApplicationContextFactory", ex); } } private <T> T getFromSpringFactories(WebApplicationType webApplicationType, BiFunction<ApplicationContextFactory, WebApplicationType, T> action, Supplier<T> defaultResult) { for (ApplicationContextFactory candidate : SpringFactoriesLoader.
Flex弹性盒布局 前言 布局的传统解决方案,基于盒状模型,依赖 display 属性 + position 属性 + float 属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。
2009 年,W3C 提出了一种新的方案—— Flex 布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。
一、什么是Flex弹性布局? Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。
CSS3 弹性盒( Flexible Box 或 flexbox),是一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有恰当的行为的布局方式。
引入弹性盒布局模型的目的是提供一种更加有效的方式来对一个容器中的子元素进行排列、对齐和分配空白空间。
弹性盒子由弹性容器(Flex container)和弹性子元素(Flex item)组成。
弹性容器通过设置 display 属性的值为 flex 或 inline-flex将其定义为弹性容器。
弹性容器内包含了一个或多个弹性子元素。
任何一个容器都可以指定为 Flex 布局。
.box{ display: flex; } 行内元素也可以使用 Flex 布局。
.box{ display: inline-flex; } Webkit 内核的浏览器,必须加上-webkit前缀。
.box{ display: -webkit-flex; /* Safari */ display: flex; } 注意:设为 Flex 布局以后,子元素的float、clear和vertical-align属性将失效。
二、Flex布局的好处 简单易懂:与传统的布局方式相比,Flex布局的语法和理解起来更加简单,容易上手。弹性和自适应:Flex布局能够自动适应不同尺寸的屏幕,让页面更具有弹性。等高布局:Flex布局可以方便地实现多列等高布局。对齐和排序:Flex布局支持各种对齐方式,包括水平和垂直对齐,并且可以通过设置order属性对子元素进行排序。可以与传统布局结合使用:Flex布局并不是完全取代传统的布局方式,它可以与传统布局方式结合使用,实现更灵活的布局效果。 三、基本概念 采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"
此源码是获取界面所有文字,希望对auto.js技术爱好者有所启示。
/** //脚本学习交流+741318378 订制开发自动化脚本vx 104810314同扣扣 * @method getAllText * @param setting 是个对象, 决定是否获取text,desc,id,以及是否去重; 默认获取text和desc,不获取id,默认去重 * @desc 默认设置为{ getText: true, getDesc: true, getId: false, removeRepetitiveElements: true } * @desc 获取页面所有文字,可以指定text,desc,id三个中的任意几个 * @return 所有文字组成的数组 */ function getAllText(setting) { var setting = setting || {} var defaultSetting = { getText: true, getDesc: true, getId: true, removeRepetitiveElements: true } Object.assign(defaultSetting, setting); log(defaultSetting) var allStr = [] var getDescAndTextAndIdOfNode = function(node) { if (node) { if (defaultSetting.
CSDN blog relies on points to improve its level. Blog points are the recognition and reward of CSDN for the efforts of users, and are also an important standard to measure the level of blogs. Blog rank will also be uniquely determined by blog points.
If you want to quickly level up, you need to follow the CSDN rules to get points, which are as follows:
1. For each original or translated article published: 10 points;
上次通信的时候用的是自带的编解码器,今天自己实现一下自定义的。
1、自定义一下协议
//协议类 @Data public class Protocol<T> implements Serializable { private Long id = System.currentTimeMillis(); private short msgType;// 假设1为请求 2为响应 private T body; } //消息请求体 @Data public class RequestMsg implements Serializable { private String msg; private String other; } //消息响应体 @Data public class ResponseMsg implements Serializable { private String result; private String error; } 2、定义编解码器import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; //编码器 public class EnCodeMsg extends MessageToByteEncoder<Protocol<Object>> { @Override protected void encode(ChannelHandlerContext channelHandlerContext, Protocol<Object> msg, ByteBuf byteBuf) throws Exception { Serialization serialization = new JdkSerialization(); byte[] body = serialization.
前言 Python是一种广泛应用于爬虫的高级编程语言,它提供了许多强大的库和框架,可以轻松地创建自己的爬虫程序。在本文中,我们将介绍如何使用Python实现简单的爬虫功能,并提供相关的代码实例。
如何实现简单的爬虫 1. 导入必要的库和模块 在编写Python爬虫时,我们需要使用许多库和模块,其中最重要的是requests和BeautifulSoup。Requests库可以帮助我们发送HTTP请求,并从网站上获取数据,而BeautifulSoup可以帮助我们从HTML文件中提取所需的信息。因此,我们需要首先导入这两个库。
import requests from bs4 import BeautifulSoup 2. 发送HTTP请求 在爬虫程序中,我们需要向网站发送HTTP请求,通常使用GET方法。Requests库提供了一个get()函数,我们可以使用它来获取网站的HTML文件。这个函数需要一个网站的URL作为参数,并返回一个包含HTML文件的响应对象。我们可以使用text属性来访问HTML文件的文本内容。
url = "https://www.example.com" response = requests.get(url) html = response.text 在发送HTTP请求时,我们需要注意是否需要添加用户代理和头信息。有些网站会检查用户代理和头信息,如果没有正确的值,它们就会拒绝我们的请求。为了避免这种情况,我们可以在HTTP请求中添加用户代理和头信息。我们可以使用requests库的headers选项来添加头信息。
headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"} response = requests.get(url, headers=headers) 3. 解析HTML文件 在获取了网站的HTML文件之后,我们需要从中提取我们想要的信息。为此,我们需要使用BeautifulSoup库,它提供了许多强大的函数和方法,可以轻松地解析HTML文件。
我们可以使用BeautifulSoup函数将HTML文件转换为BeautifulSoup对象。然后,我们可以使用find()、find_all()等方法来查找HTML文件中的元素。这些方法需要一个标签名称作为参数,并返回一个包含所选元素的列表或单个元素。
soup = BeautifulSoup(html, "html.parser") title = soup.find("title").text 为了从HTML文件中提取更多的信息,我们需要了解CSS选择器。CSS选择器是一种用于选择HTML元素的语法,类似于CSS中的样式选择器。我们可以使用CSS选择器来获取HTML文件中特定元素的信息。例如,我们可以使用select()方法和一个CSS选择器来选择一个类别的所有元素。
items = soup.select(".item") for item in items: title = item.select(".title")[0].text price = item.
java中异步socket类的实现和源代码
我们知道,java中socket类一般操作都是同步进行,常常在read的时候socket就会阻塞直到有数据可读或socket连接断开的时候才返回,虽然可以设置超时返回,但是这样比较低效,需要做一个循环来不停扫描数据是否可读。看来,在同一个线程中,要是想实现异步读写不太容易。
下面介绍的这个类实现了伪异步socket通讯。基本思想就是在现有socket类的基础上进行封装,当socket连接建立成功后,立即创建一个socket数据接收线程,专门负责阻塞式的socket读取(read),而当前线程负责数据的发送(send)。另外定义了一个接口,包括了socket的各种事件的回调。我们要实现这个接口,在接口实现类中创建异步socket对象,并且传递接口类到异步socket对象中,目的是有socket事件的时候回调我们的方法。
下面是接口:
SocketExHandler.java package com.ly.net;
import java.net.*; /**
* Title: * Description:
* Copyright: Copyright (c) 2001
* Company: http://dozb.blogchina.com
* @author dozb
* @version 1.0
*/
/**
* 异步Socket Client Interface
* 使用方法:
* 1.定义类 MySocketClientEx 实现SocketExHandler接口,实现 OnReceive OnClose OnConnect 事件
* 2.在类中实现start方法 MySocketEx = new SocketEx(this,ip,port)
* 3.在类中实现stop方法 delete MySocketEx
* 4.当有数据到达时会触发OnReceive事件
* 5.当对方SOCKET关闭时会触发OnClose事件
* 6.当SOCKET建立时会触发OnConnect事件
*/
/**
* 异步Socket Server Interface
* 使用方法:
* 1.
在前端开发中,为适应各种需求,很多情况下都需要将icon图标进行转换以满足需求。将png转为iconfont是一种比较好的方法。本文介绍一款自动直接将png图片转为svg格式的vite插件,可在vue和react框架中使用。
npm add vite-plugin-png-to-svg --save-dev
使用配置: // vite.config import {defineConfig} from 'vite' import pngToSvg from 'vite-plugin-png-to-svg' export default defineConfig({ plugins: [ pngToSvg({ // 所有参数为可选 pngPath: "/src/assets/png", // png图片位置,默认/src/assets/png svgPath: "/src/assets/svg", // 生成的svg保存位置,默认/src/assets/svg isReplace: false, // 替换指定文件内容中的png图片,默认false include: ['vue', 'tsx'], // 指定文件后缀,默认['vue','tsx']。isReplace=true时有效 replaceType: 'img' // 替换模式,img/svg两种。默认img。isReplace=true时有效 }) ] }) 使用方法: 方法1.将需要转换的png图片保存至pngPath配置目录下,如/src/assets/png。在dev或build模式下会自动将目录下的png转换为svg并保存在指定位置。最后在页面中引用即可。
方法2.设置isReplace为true,同时将需转换的img添加data-src="svg"标识,即可自动将指定后缀文件内容中的png图片替换为svg内容。
<div> <img src="../assets/29.png" data-src="svg"> </div> <!--当replaceType模式为img时,将转换为以下内容--> <div> <img src="/src/assets/svg/29.svg" data-src="svg"> </div> <!--当replaceType模式为svg时,将转换为以下内容--> <div> <svg xmlns="http://www.w3.org/2000/svg" width="416" height="419" viewBox="0 0 416 419"
Android Studio 2022.2.1项目迁移报错1、No variants found for ':app'. Check build files to ensure at least one variant exists. at:,2、manifest merger failed with multiple errors see logs,3、module java.base does not “opens java.io“ to unnamed module。
PS:(2022.2.1)新版AS。。。
1,JDK17
2,AGP8.0,我仅更为7.1+
1,No variants found for ':app'. Check build files to ensure at least one variant exists. at: 网上解决方案 Android SDK Build-tools版本不匹配,去AS的Settings下载自己需要的SDK相关配置,但对我不生效。
java - No variants found for 'app'. Check build files to ensure at least one variant exists: Android Studio - Stack Overflow 分享我的解决方法: repositories { flatDir { dirs 'libs' } // maven { // url "