NanoLog起步笔记-5-客户端简要描述
nonolog起步笔记-5-客户端简要描述
- 客户端的简要的设计图路
- notify模式
- 服务端最好分两个核
- NanoLog::setLogLevel(NOTICE);
- 从 NANO_LOG 开始
- NANO_LOG
- compiling time的语句
- getNumNibblesNeeded:得到prompt中,number的数量
- countFmtParams:得到所有的参数的个数
- analyzeFormatString:制作参数队列
- NanoLogInternal::checkFormat 暂时略过。
- 这一段注释的意思:
- NanoLogInternal::log
- NanoLogInternal::log 的定义
- 函数的模板参数
- 模板参数N
- 模板参数M
- 模板参数Ts
- StaticLogInfo info
客户端是大头。nanolog的服务端中规中矩,没有太多需要描述之处。但客户端相对复杂得多。
客户端的简要的设计图路
Nanolog客户端,是以线程为最小粒度设计的、压入数据不管,由server端来取走的的模式设计的。
所以,客户端有最大等待时长。超时则抛弃。
notify模式
当然,要注意,有notifiy模式,这种模式下,服务端不再是轮询。而是等待客户端通知。
在数据量小的时候、核心特别紧张时,可以考虑。
服务端最好分两个核
因为,默认情况下,server端,不论客户端的buffer有无数据,都要忙轮询,在外界看来,这个核 的用户占CPU占用率是100。
另外注意,如果核心相对充裕,至少要给log服务端编两个核,以免服务线程和异步io线程相互干扰。
上面这些不是我们要讲的,所以,还是到正题。
NanoLog::setLogLevel(NOTICE);
这个没什么好说的。
// Optional: Set the minimum LogLevel that log messages must have to be// persisted. Valid from least to greatest values are// DEBUG, NOTICE, WARNING, ERRORNanoLog::setLogLevel(NOTICE);
不过可以看到,返回的时间很早。
这里我需要自我反省一下,最初看到这段代码,当时忙别的,没仔细看,以后是很靠后。
后来仔细看才明白,前面的话,都是在编译阶段固化的。
所以,这段是没有问题的,几乎确是在第一句就检查log打印级别。已经做到了最快。
从 NANO_LOG 开始
NANO_LOG
NANO_LOG(DEBUG, "This message wont be logged since it is lower ""than the current log level.");
宏展开
/*** NANO_LOG macro used for logging.** \param severity* The LogLevel of the log invocation (must be constant)* \param format* printf-like format string (must be literal)* \param ...UNASSIGNED_LOGID* Log arguments associated with the printf-like string.*/
#define NANO_LOG(severity, format, ...) do { \constexpr int numNibbles = NanoLogInternal::getNumNibblesNeeded(format); \constexpr int nParams = NanoLogInternal::countFmtParams(format); \\/*** Very Important*** These must be 'static' so that we can save pointers* to these variables and have them persist beyond the invocation.* The static logId is used to forever associate this local scope (tied* to an expansion of #NANO_LOG) with an id and the paramTypes array is* used by the compression function, which is invoked in another thread* at a much later time. */ \static constexpr std::array<NanoLogInternal::ParamType, nParams> paramTypes = \NanoLogInternal::analyzeFormatString<nParams>(format); \static int logId = NanoLogInternal::UNASSIGNED_LOGID; \\if (NanoLog::severity > NanoLog::getLogLevel()) \break; \\/* Triggers the GNU printf checker by passing it into a no-op function.* Trick: This call is surrounded by an if false so that the VA_ARGS don't* evaluate for cases like '++i'.*/ \if (false) { NanoLogInternal::checkFormat(format, ##__VA_ARGS__); } /*NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg)*/\\NanoLogInternal::log(logId, __FILE__, __LINE__, NanoLog::severity, format, \numNibbles, paramTypes, ##__VA_ARGS__); \
} while(0)
compiling time的语句
getNumNibblesNeeded:得到prompt中,number的数量
类似%d,%ld,%7.2f这类的。
constexpr int numNibbles = NanoLogInternal::getNumNibblesNeeded(format);
countFmtParams:得到所有的参数的个数
constexpr int nParams = NanoLogInternal::countFmtParams(format);
analyzeFormatString:制作参数队列
static constexpr std::array<NanoLogInternal::ParamType, nParams> paramTypes = NanoLogInternal::analyzeFormatString<nParams>(format)
这句话中,NanoLogInternal::ParamType, 是模板参数,它本身是一个枚举。所以,类似com编程中的variant类型,为所有的不同的类型,提供一个相同的锚点。
nParams,这个呢是重点。
这里被用到了至少两次,后面在NanoLogInternal::log那里,又被用到。
因为static constexpr std::array相当于定义了静态的数组。要记住,在编译阶段,一切都是静态的,这到什么时候,C++体系也是这样。
多态的VTable虽然是在runtime赋值,但其空间分配,则在编译时就定好的。
因为是静态数组,所以,一切都需要明确。
所以,nParams这里被第一次用到:告知这个数据有多大。
第二次用到是这里,注意,nParams在这里只是一个模板参数,编译器在这里要的不是它的值,而是它的类型:
NanoLogInternal::analyzeFormatString(format)
在后面,一会我们看到,NanoLogInternal::log的调用中,nParams再一次作为类型被这个模板函数所引用。
NanoLogInternal::checkFormat 暂时略过。
if (false) { NanoLogInternal::checkFormat(format, ##VA_ARGS); }
这次我学习nanolog,一方面,是为了将之转化为ctf格式,另外两个方面,一是思考如何进一步优化,例如全面内存化;二是我们在使用中,确有错误发生。
这个错误,显然是某个程序员写的某句NANO_LOG导致,但这句话,pass过了编译器,也pass的log这个数数,直到准备将之解压为人类可读的动作时,才失败。目前我还没有时间去定位。但这也是目标之一。
这么来看,这个check,似乎也没有尽职尽责。
这一段注释的意思:
/*** Very Important*** These must be 'static' so that we can save pointers* to these variables and have them persist beyond the invocation.* The static logId is used to forever associate this local scope (tied* to an expansion of #NANO_LOG) with an id and the paramTypes array is* used by the compression function, which is invoked in another thread* at a much later time. */ \static constexpr std::array<NanoLogInternal::ParamType, nParams> paramTypes = \NanoLogInternal::analyzeFormatString<nParams>(format); static int logId = NanoLogInternal::UNASSIGNED_LOGID; \
这一段代码,用了两个前置的保留字来修饰:static constexpr
意思是上下文相关的compiling time代码展开。
例如,这一句,作者的意图是在编译时,展开NANO_LOG时,预留一个全局变量,在运行时,将之赋值,而且是唯一的值。
static int logId = NanoLogInternal::UNASSIGNED_LOGID;
注意,logId后面被以引用,或者传址的方式,传给了log函数,由该函数,为该变量在第一次运行时赋永久值。
log(int &logId,
再强调logId是注册号,一旦注册,在程序运行阶段不会再改变。是类型序号,是唯一的,不是log序号。
NanoLogInternal::log
这句显然是重点。我们详细解读之。
NanoLogInternal::log 的定义
这个主函数,我们看到内容并不多
/*** Logs a log message in the NanoLog system given all the static and dynamic* information associated with the log message. This function is meant to work* in conjunction with the #define-d NANO_LOG() and expects the caller to* maintain a permanent mapping of logId to static information once it's* assigned by this function.** \tparam N* length of the format string (automatically deduced)* \tparam M* length of the paramTypes array (automatically deduced)* \tparam Ts* Types of the arguments passed in for the log (automatically deduced)** \param logId[in/out]* LogId that should be permanently associated with the static information.* An input value of -1 indicates that NanoLog should persist the static* log information and assign a new, globally unique identifier.* \param filename* Name of the file containing the log invocation* \param linenum* Line number within filename of the log invocation.* \param severity* LogLevel severity of the log invocation* \param format* Static printf format string associated with the log invocation* \param numNibbles* Number of nibbles needed to store all the arguments (derived from* the format string).* \param paramTypes* An array indicating the type of the n-th format parameter associated* with the format string to be processed.* *** THIS VARIABLE MUST HAVE A STATIC LIFETIME AS PTRS WILL BE SAVED **** \param args* Argument pack for all the arguments for the log invocation*/
template<long unsigned int N, int M, typename... Ts>
inline void
log(int &logId,const char *filename,const int linenum,const LogLevel severity,const char (&format)[M],const int numNibbles,const std::array<ParamType, N>& paramTypes,Ts... args)
{using namespace NanoLogInternal::Log;assert(N == static_cast<uint32_t>(sizeof...(Ts)));if (logId == UNASSIGNED_LOGID) {const ParamType *array = paramTypes.data();StaticLogInfo info(&compress<Ts...>,filename,linenum,severity,format,sizeof...(Ts),numNibbles,array);RuntimeLogger::registerInvocationSite(info, logId);}uint64_t previousPrecision = -1;uint64_t timestamp = PerfUtils::Cycles::rdtsc();size_t stringSizes[N + 1] = {}; //HACK: Zero length arrays are not allowedsize_t allocSize = getArgSizes(paramTypes, previousPrecision,stringSizes, args...) + sizeof(UncompressedEntry);char *writePos = NanoLogInternal::RuntimeLogger::reserveAlloc(allocSize);auto originalWritePos = writePos;UncompressedEntry *ue = new(writePos) UncompressedEntry();writePos += sizeof(UncompressedEntry);store_arguments(paramTypes, stringSizes, &writePos, args...);ue->fmtId = logId;ue->timestamp = timestamp;ue->entrySize = downCast<uint32_t>(allocSize);#ifdef ENABLE_DEBUG_PRINTINGprintf("\r\nRecording %d:'%s' of size %u\r\n",logId, info.formatString, ue->entrySize);
#endifassert(allocSize == downCast<uint32_t>((writePos - originalWritePos)));NanoLogInternal::RuntimeLogger::finishAlloc(allocSize);
}
该函数,我们看到内容并不多。
函数的模板参数
模板参数N
这个容易理解,因为上面我们解释过了。就是上面解释的nParams。
这是它第三次再次被用到。
模板元编程,要理清,代码中用的是它的值,还是类型,这第三是引用它的类型。
template<long unsigned int N, int M, typename… Ts>
这句话,我并没有完全看懂,毕竟有几年没用C++了。
这里是预期的类型。反正我是觉得有点怪,模板的作用主要是类型的泛型,这里又指定,其实有点难以理解,但是这个在C++中叫预期类型,其实你也可以叫它脱了裤子放屁,无非是想编译器帮你报错(这个错,可能让它的设计整体上陷入自己怀疑)。
反正,你要信我,相认这里编译器并不是从模型预定的类型来计算大小,而是根据nParams的类型。
这就是这句代码的解释:
const std::array<ParamType, N>& paramTypes
。
个人的看法是,之所以写得这么复杂,是因为我们现在的编译器,目前也只能到这个水平。
因为这个参数,是在编译时就全面完成了初始化工作。所以,我们用了泛型,但却是为了能编译过。也许人类未来的编译器,将更加强大,写出更让人容易理解的代码。
再啰嗦一句,在最初没有C++17时,google就开发了nanolog,所以,相对旧一点的代码,是允许不用C++17的,所以,C++17的这些新特性,对于google团队来说,也是新的知识。所以,现在我看这些代码,也不那么觉得奇怪写得有时不那么让人能直观地理解。
之前google是利用编译前的预处理来实现的。这个我不清楚,可能是相当于自己写了编译器的插件,编译之后,进行了处理。
模板参数M
这个,确实第一时间,我不敢肯定,现在基本肯定,确实是编译器会根据用户(业务程序员)编写代码,自动计算出可变参数的数量。
M:表示paramTypes数组的长度,同样由编译器自动推断。这个参数与N的作用相似,它确保了数组的大小与格式字符串中的参数数量相匹配。
模板参数Ts
Ts…:这是一个模板参数包,它包含了传递给log函数的所有参数的类型。这个参数包用于在编译时进行类型检查和类型相关的操作,例如计算参数的数量(sizeof…(Ts))以及在运行时存储参数的实际值。
好吧,这一项我去查了查。并没有完全理解。
…这样的可变参数,我印象中,C语言的解释是双指针数组,似乎。
这样也就能理解为什么sizeof不会错。
即为什么函数第二行的断言能通过的原因:
assert(N == static_cast<uint32_t>(sizeof…(Ts)));
我是这么猜的。
StaticLogInfo info
这一段,是精华中的精华。后现我打算专门在一篇中来写。
它的作用是注册。
具体作用,如果看过CTF,基实这段,与ctf的metadata,或者schema,或者在TMN中被称为MIB(主信息库),是一样的。
所不同的是,一般的schema是,用户手工定义,并且在系统启动前,喂给系统的;
这里的是动态制作出来的。
if (logId == UNASSIGNED_LOGID) {const ParamType *array = paramTypes.data();StaticLogInfo info(&compress<Ts...>,filename,linenum,severity,format,sizeof...(Ts),numNibbles,array);RuntimeLogger::registerInvocationSite(info, logId);}
然后它被注册。
之后是分配内存。
这些内存是在当前的线程的客户端的私有块中分配。
相关文章:
NanoLog起步笔记-5-客户端简要描述
nonolog起步笔记-5-客户端简要描述 客户端的简要的设计图路notify模式服务端最好分两个核 NanoLog::setLogLevel(NOTICE);从 NANO_LOG 开始NANO_LOGcompiling time的语句getNumNibblesNeeded:得到prompt中,number的数量countFmtParams:得到所…...
Flink:入门介绍
目录 一、Flink简介 2.1 Flink 架构 2.2 Flink 应用程序 运行模式 二、Flink 集群 部署 2.1 本地集群模式 2.1.1 安装JDK编辑 2.1.2 下载、解压 Flink 2.1.3 启动集群 2.1.4 停止集群 2.2 Standalone 模式 2.2.0 集群规划 2.2.1 安装JDK 2.2.2 设置免密登录 2…...
目标跟踪领域经典论文解析
亲爱的小伙伴们😘,在求知的漫漫旅途中,若你对深度学习的奥秘、JAVA 、PYTHON与SAP 的奇妙世界,亦或是读研论文的撰写攻略有所探寻🧐,那不妨给我一个小小的关注吧🥰。我会精心筹备,在…...
网络编程 | TCP套接字通信及编程实现经验教程
1、TCP基础铺垫 TCP/IP协议簇中包含了如TCP、UDP、IP、ICMP、ARP、HTTP等通信协议。TCP协议是TCP/IP协议簇中最为常见且重要的通信方式之一,它为互联网上的数据传输提供了可靠性和连接管理。 TCP(Transmission Control Protocol,传输控制协议…...
SAP导出表结构并保存到Excel 源码程序
SAP导出表结构并保存到Excel,方便写代码时复制粘贴 经常做接口,需要copy表结构,找到了这样一个程程,特别有用。 01. 先看结果...
Linux下redis环境的搭建
1.redis的下载 redis官网下载redis的linux压缩包,官网地址:Redis下载 网盘链接: 通过网盘分享的文件:redis-5.0.4.tar.gz 链接: https://pan.baidu.com/s/1cz3ifYrDcHWZXmT1fNzBrQ?pwdehgj 提取码: ehgj 2.redis安装与配置 将包上传到 /…...
REDMI瞄准游戏赛道,推出小屏平板
近日,REDMI推出了一款8.8英寸的小屏平板,引发市场关注。该平板采用LCD屏幕,搭载天玑9400处理器,定位游戏市场,意在开拓小屏平板的新领域。 小屏平板新尝试 这款REDMI平板未追随大屏潮流,而是选择了8…...
springai结合ollama
目录 ollama 介绍 使用 下载: 安装: 点击这个玩意next就行了。 运行 spring ai使用ollama调用本地部署的大模型 加依赖 配置yml 写代码 ollama 介绍 官网:Ollama Ollama是一个用于部署和运行各种开源大模型的工具; …...
React第十三节开发中常见问题之(视图更新、事件处理)
一、视图更新有哪些方案? useState用法介绍 1、对于数据变量 正常的增删改查,只会让数据更新,但是不会触发 React 视图的更新; 如: <script lang"jsx">const baseTable [{name:Andy, age: 18, id…...
【Appium报错】安装uiautomator2失败
目录 1、通过nmp安装uiautomator2:失败 2、通过 Appium 的平台直接安装驱动程序 3、通过pip 来安装 uiautomator2 1、通过nmp安装uiautomator2:失败 我先是通过npm安装的uiautomator2,也显示已经安装成功了: npm install -g …...
DataSophon集成CMAK KafkaManager
本次集成基于DDP1.2.1 集成CMAK-3.0.0.6 设计的json和tar包我放网盘了. 通过网盘分享的文件:DDP集成CMAK 链接: https://pan.baidu.com/s/1BR70Ajj9FxvjBlsOX4Ivhw?pwdcpmc 提取码: cpmc CMAK github上提供了zip压缩包.将压缩包解压之后 在根目录下加入启动脚本…...
Ubuntu22.04深度学习环境安装【显卡驱动安装】
前言 使用Windows配置环境失败,其中有一个包只有Linux版本,Windows版本的只有python3.10的,所以直接选用Linux来配置环境,显卡安装比较麻烦,单独出一期。 显卡驱动安装 方法一:在线安装(操作…...
21届秋/校招面经
开篇先说一下我自身情况,东南大学本科计算机科学与技术专业毕业,gpa3.2/4.8。零零散散搞过一年多ACM,去年(2019)在icpc上海站拿了铜之后增加了信心(因为当时训练总时间半年不到),于是…...
相机动态/在线标定
图1 图2 基本原理 【原理1】平行线在射影变换后会交于一点。如图所示,A为相机光心,蓝色矩形框为归一化平面,O为平面中心。地面四条黄色直线为平行且等距的车道线。HI交其中两条车道线于H、I, 过G作HI的平行线GM交车道线于M。HI、GM在归一化平面上的投影分别为JK、PN,二者会…...
MySQL 8.0 新特性汇总
文章目录 前言1. 运维管理 1.1 可持久化变量1.2 管理员端口1.3 资源组1.4 数据库粒度只读1.5 show processlist 实现方式1.6 加速索引创建速度1.7 控制连接的内存使用量1.8 克隆插件1.9 mysqldump 新增参数1.10 慢日志增强1.11 快速加列1.12 InnoDB 隐藏主键1.13 Redo 配置1.14…...
Resnet C ++ 部署 tensort 部署(四)
Resnet C 部署 pytorch功能测试(一) Resnet C 部署 模型训练(二) Resnet C 部署 模型测试&转 onnx(三) Resnet C 部署 tensort 部署(四) 之后,开始onnx 转trt 部…...
《Java核心技术I》对并发散列映射的批操作
对并发散列映射的批操作 Java API提供了批处理,计时其他线程处理映射,这些操作也能安全的执行。 3种不同操作: search(搜索),为每个键或值应用一个函数,直到函数生成一个非null的结果,然后搜索终止&…...
记录一次使用git无权限的问题排查
正常的配置了公私钥之后,在gitlab中也存储了配对的公钥,但当使用git clone 时,总是报无权限 由于在这台机器中添加了多个公私钥,有点复杂,我们可以使用命令 ssh -vvvT 调试一下 ssh -vvvT yourGitlabAddr...
appium学习之二:adb命令
1、查看设备 adb devices 2、连接 adb connect IP:端口 3、安装 adb install xxx.apk 4、卸载 adb uninstall 【包名】 5、把对应目录下的1.txt文件传到手机sdcard下 adb push 1.txt /sdcard 6、进入对应的设备里 adb shell 7、切入sdcard目录 cd /sdcard 8、ls 查…...
Linux Vi/Vim使用 ⑥
掌握 CentOS 7 下的 Vi/Vim 编辑器:从安装到精通 在 CentOS 7 系统的日常运维、编程开发以及各类文本处理场景中,Vi/Vim 编辑器都是不可或缺的得力工具。它以轻量、高效、功能强大著称,虽然初次上手有一定学习门槛,但掌握之后便能…...
JCR一区牛顿-拉夫逊优化算法+分解对比!VMD-NRBO-Transformer-BiLSTM多变量时序光伏功率预测
JCR一区牛顿-拉夫逊优化算法分解对比!VMD-NRBO-Transformer-BiLSTM多变量时序光伏功率预测 目录 JCR一区牛顿-拉夫逊优化算法分解对比!VMD-NRBO-Transformer-BiLSTM多变量时序光伏功率预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.中科院…...
easyExcel实现表头批注
背景: 网上大部分都不能直接使用,为此总结一个方便入手且可用的工具,用自定义注解实现 依赖包: <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>…...
Pytest测试用例使用小结
基础使用 Pytest 测试用例实现代码 import pytest from server.service import Servicepytest.fixture def service():return Service(logger)class TestService:classmethoddef setup_class(cls):"""初始化设置一次:return:"""logger.info(&q…...
LeetCode题练习与总结:132 模式--456
一、题目描述 给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]、nums[j] 和 nums[k] 组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。 如果 nums 中存在 132 模式的子序列 &a…...
IdentityServer4框架、ASP.NET core Identity
OAuth2.0 IdentityServer4 官网 中文官网 ASP.NET Core Identity提供了一个用来管理和存储用户账户的框架. IdentityServer4是基于ASP.NET Core实现的认证和授权框架,是对OpenID Connect和OAuth 2.0协议的实现。 IdentityServer是一个中间件,它可以添加符合OpenID…...
【分子材料发现】——GAP:催化过程中吸附构型的多模态语言和图学习(数据集处理详解)(二)
Multimodal Language and Graph Learning of Adsorption Configuration in Catalysis https://arxiv.org/abs/2401.07408Paper Data: https://doi.org/10.6084/m9.figshare.27208356.v2 1 Dataset CatBERTa训练的文本字符串输入来源于Open Catalyst 2020 (OC20…...
SpringBoot开发过程中经常遇到问题解决方案分享
目录 1. Spring Boot应用启动缓慢 2. 数据库连接池配置问题 3. Spring Boot应用无法连接外部服务 4. 配置文件读取不生效 5. Spring Boot应用的日志输出不完整 6. Spring Boot中的Transactional事务管理问题 1. Spring Boot应用启动缓慢 问题原因: Spring Boo…...
AR眼镜_消费级工业AR智能眼镜主板硬件解决方案
AR眼镜的研发是一项复杂的软硬件集成工程,它需要在摄影、音频、交互和连接等多个方面提供卓越的基础体验,因此产品的每个细节都显得尤为重要。 在设计AR眼镜时,重量、体积和散热性能都是必须认真考量的关键因素。在芯片平台的选择上ÿ…...
Springboot 核心注解
Spring Boot 是一个基于 Spring 框架的扩展,旨在简化新 Spring 应用的初始搭建以及开发过程。它通过自动配置和约定优于配置的原则,减少了开发者的工作量。Spring Boot 提供了一组核心注解和 Starter 依赖管理工具来帮助开发者快速启动项目。 1. Spring…...
Nacos集群搭建【Oracle作外部数据源】
一、知识点分析 1.Nocas是什么? Nacos是一个动态服务发现、配置管理和服务管理平台。 1.1定义与背景: Nacos,全称为Dynamic Naming and Configuration Service,是由阿里巴巴开源的云原生应用配套工具。它旨在简化微服务架…...
网站seo站外优化/网页设计可以自学吗
大家都知道网站对一个企业的网络营销和推广来说非常重要,现在越来越多的企业选择自助建站,最大优点的节约费用,没有建站经验也能做出一个功能强大,甚至比专业网站建设公司更专业的网站,自助建站分为自助建站系统和在线…...
电子商务网站建设规划心得/江西seo
2019独角兽企业重金招聘Python工程师标准>>> JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。 JPA 的目标之一是制定一个可以由很多供应商实现的API,并且…...
网站建设报告实训步骤/百度客服电话号码
统一项目管理平台(UMPlatForm.NET) 4.10 用户权限管理模块 统一项目管理平台(UMPlatForm.NET),基于.NET的快速开发、整合框架。 4.10用户权限管理模块 在实际应用中我们会发现,权限控制会经常变动,如&#…...
临沂做网站的在哪里/网红推广一般怎么收费
需求:将商品表的相同型号的商品中价格为[[0,0]]的异常数据标记为404 //collection_name MongoDB集合名 //ModelName 字段名 //Tiered 字段名,值[[0,0]]db.collection_name.find({"error":404}).count(); var arr db.collection_name.aggregate([{ $group: { _id : $…...
建网站和建小程序多少钱/谷歌seo外链平台
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼昂达v975w双系统(win10x86安卓5.1R1)安装教程微软也确实令人失望,在win10下,app还是这样子,所以楼主萌生了在不刷v975i的bios状况刷安卓,而是在win下的bios装上x86安卓玩耍安卓的海量…...
一级a做愛网站伦理片/互联网平台
本文实例讲述了yii2控制器Controller Ajax操作的方法。分享给大家供大家参考,具体如下:public function actionSample(){if (Yii::$app->request->isAjax) {$data Yii::$app->request->post();$searchname explode(":", $data[se…...