Quantcast
Channel: CSDN博客推荐文章
Viewing all 35570 articles
Browse latest View live

【比特币】BIP-0021 详细说明

$
0
0

BIP-0021 详细说明

  BIP: 21
  Layer: Applications
  Title: URI方案
  Author: Nils Schneider <nils.schneider@gmail.com>
          Matt Corallo <bip21@bluematt.me>
  Comments-Summary: No comments yet.
  Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0021
  Status: Final
  Type: Standards Track
  Created: 2012-01-29

这个BIP是Luke Dashjr早期BIP 0020的一个修改。 BIP 0020基于Nils Schneider早期的文件。 BIP 0020中的替代支付金额已被删除。

摘要

这个BIP提出了一个用于支付比特币的URI方案。

动机

这个URI方案的目的是让用户只需点击网页上的链接或扫描QR码即可轻松付款。

规范

处理的一般规则(重要!)

比特币客户端不得在未获得用户授权的情况下对URI进行操作。 他们应该要求用户手动批准每个付款,但在某些情况下,他们可能会允许用户自动做出这个决定。

操作系统集成

图形比特币客户端应该注册自己作为默认的“比特币:”URI方案的处理程序,如果没有其他处理程序已经注册。 如果已经有一个注册处理程序,它们可能会提示用户在第一次运行客户程序时更改一次。

一般格式

比特币URI遵循RFC 3986中规定的URI的通用格式。路径组件由比特币地址组成,查询组件提供额外的支付选项。

查询组件的元素可能包含有效范围之外的字符。 这些必须首先根据UTF-8进行编码,然后按照RFC 3986中所述,相应的UTF-8序列的每个八位字节必须进行百分比编码。

ABNF语法

 bitcoinurn     = "bitcoin:" bitcoinaddress [ "?" bitcoinparams ]
 bitcoinaddress = *base58
 bitcoinparams  = bitcoinparam [ "&" bitcoinparams ]
 bitcoinparam   = [ amountparam / labelparam / messageparam / otherparam / reqparam ]
 amountparam    = "amount=" *digit [ "." *digit ]
 labelparam     = "label=" *qchar
 messageparam   = "message=" *qchar
 otherparam     = qchar *qchar [ "=" *qchar ]
 reqparam       = "req-" qchar *qchar [ "=" *qchar ]

这里,“qchar”对应于RFC 3986 URI查询组件的有效字符,不包括此BIP作为分隔符的“=”和“&”字符。

计划组件(“比特币:”)不区分大小写,实现必须接受大写和小写字母的任意组合。 其余的URI区分大小写,包括查询参数键。

查询键

  • 标签:该地址的标签(例如,接收者的姓名)
  • 地址:比特币地址
  • 消息:向用户描述交易的消息(请参阅下面的示例)
  • 大小:基础比特币单位数量(见下文)
  • (其他):可选,用于将来的扩展

转账金额/大小

如果提供金额,则必须用十进制BTC指定。 所有金额必须不包含逗号,并使用句点(。)作为分隔符来分隔整数和小数部分。即 金额= 50.00或金额= 50被视为50 BTC,金额= 50,000.00无效。

比特币客户端可以以任何形式来显示金额,而不是用来欺骗用户的。 他们应该选择一种最容易混淆的格式,只有在最合理的情况下才能提供所要求的金额。 例如,只要大多数用户以BTC为单位工作,即使mBTC或TBC会对数量进行更合理的解释,也应始终在BTC中显示值。

原理

付款标识符,而不是个人标识符

目前的最佳做法是每个交易都应该使用一个独特的地址。 因此,URI方案不应该代表个人信息的交换,而应该是一次性支付。

可访问性(URI方案名称)

如果外部的人碰巧看到这样的URI,那么URI方案名称就已经给出了描述。 然后快速搜索,以帮助他们找到支付所需的资源。 其他提出的名字听起来更加神秘; 有人因为好奇而谷歌浏览器的机会要小得多。 另外,很可能,他会发现大部分技术规格 - 而不是比特币的最佳介绍。

向前兼容

被认为需要前缀的变量被认为是必需的。 如果一个客户没有实现任何以req-为前缀的变量,它必须考虑整个URI是无效的。 任何其他没有实现的变量,但是没有以req-开头的前缀,都可以被安全的忽略。

向后兼容

在写这个BIP时,有几个客户已经实现了一个类似于这个的比特币:URI方案,但是通常没有额外的“req-”前缀要求。 因此,为了让客户开发人员能够发布新的版本,建议在完成本BIP的6个月的宽限期之后,以任务关键的方式使用前缀的附加变量,以及 老客户升级。

附录

简单的语法

本部分是非规范性的,并不涵盖所有可能的语法。 请参阅上面的BNF语法的规范语法。

[foo]表示可选,是占位符

 bitcoin:<address>[?amount=<amount>][?label=<label>][?message=<message>]

例子

只有地址:

 bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W

带着名字:

 bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?label=Luke-Jr

请求20.30 BTC到“Luke-Jr”:

 bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=20.3&label=Luke-Jr

请求50 BTC的消息:

 bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=50&label=Luke-Jr&message=Donation%20for%20project%20xyz

一些未来版本的变量是(当前)不了解和要求,因此是无效的:

 bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-somethingyoudontunderstand=50&req-somethingelseyoudontget=999

一些未来版本的变量,(当前)不明白,但不是必需的,因此是有效的:

 bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?somethingyoudontunderstand=50&somethingelseyoudontget=999

字符必须是正确的URI编码。

参考实现

比特币客户端

  • Bitcoin-Qt支持旧版本的比特币URI(即没有req-前缀),与Windows和KDE集成为70f55355e29c8e45b607e782c5d76609d23cc858。

参考资料

作者:diandianxiyu 发表于2017/11/10 10:36:58 原文链接
阅读:14 评论:0 查看评论

LeetCode-713:Subarray Product Less Than K (乘积小于K的子数组个数) -- medium

$
0
0

Question

Your are given an array of positive integers nums.

Count and print the number of (contiguous) subarrays where the product of all the elements in the subarray is less than k.

Example 1:

Input: nums = [10, 5, 2, 6], k = 100
Output: 8

Explanation: The 8 subarrays that have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6].
Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k.

Note:

  • 0 < nums.length <= 50000.
  • 0 < nums[i] < 1000.
  • 0 <= k < 10^6.

问题解析:

给定数组,和整数K,计数数组中所有满足元素乘积小于K的连续子数组的个数。

Answer

Solution 1:

双指针遍历。

  • 该题目主要的解题思路是寻找每步相同的计数规律。
  • 按照一般的思维,要想记录连续子数组需要从左向右遍历数组。
  • 这里最重要的就是处理乘积大于K的情况,需要丢弃最前面的元素,那么说明需要有一个指针记录最前面元素的位置。
  • 在不大于K的情况下,则累加每次加入新元素后子数组的个数。
class Solution {
    public int numSubarrayProductLessThanK(int[] nums, int k) {
        if ( k <= 1) return 0;

        int n = nums.length;
        long p = 1l;
        int i = 0, total = 0;
        for (int j = 0; j < n; j++){
            p *= nums[j];
            while (p >= k){
                p /= nums[i];
                i++;
            }
            total += (j - i + 1);
        }

        return total;
    }
}
  • 时间复杂度:O(n),空间复杂度:O(1)
作者:Koala_Tree 发表于2017/11/10 10:41:43 原文链接
阅读:0 评论:0 查看评论

Spring Cloud视频

$
0
0

à 从零开始学Spring Cloud

http://study.163.com/course/introduction/1004638001.htm

 

 

 

====================================================

从零开始学Spring Cloud视频

===================================================

 

1. 适合人群

Spring Boot基础的人群。

 

2.使用技术

(1)spring boot,使用版本:1.5.8

 

(2)spring cloud ,使用版本:Dalston.SR4

 

(3)Netflix Eureka

 

(4)Netflix Ribbon

 

(5)Feign

 

(6)Netflix Hystrix

 

(7)Spring Clou Config(Git/SVN/Local)

 

(8)Netflix Zuul

 

(9)Spring Cloud Bus

 

3.技术图谱



 

 

4.课程目录

第一章 Spring Boot 介绍

 

1、Spring Cloud课程目录+使用技术+适合人群

 

2、Spring Cloud 概念

 

 

第二章 Spring Cloud服务发现组件

 

1、Spring Cloud服务提供者与服务消费者

 

2、Spring Cloud 服务发现与服务注册概念

 

3、Spring Cloud 服务发现组件Eureka实现

 

4、Spring Cloud 服务消费者(Ribbon)

 

5、Spring Cloud 服务消费者(Feign)

 

 

第三章 Spring Cloud 断路器

 

1、Spring Cloud 断路器(Ribbon)

 

2、Spring Cloud 断路器(Feign)

 

 

第四章 Spring Cloud 分布式配置中心

 

1、Spring Cloud 分布式配置中心(git)

 

2、Spring Cloud 分布式配置中心(svn)

 

3、Spring Cloud 分布式配置中心(Local)

 

4、Spring Cloud微服务获取配置

 

 

第五章Spring Cloud 服务网关

 

1、Spring Cloud 服务网关

 

2、Spring Cloud 服务网关-过滤器

 

 

第六章Spring Cloud 消息总线

 

1、Spring Cloud 消息总线

 

2、Spring Cloud消息总线-改进版

 

 

第七章Spring Cloud源代码

 

1、Spring Cloud源代码批量打包下载+PPT(网页PC端下载)

 

 

 

传送门

 

 

 

传送门

 

 


作者:linxingliang 发表于2017/11/10 11:50:47 原文链接
阅读:6 评论:0 查看评论

BZOJ1911[Apio2010]特别行动队(洛谷P3628)

$
0
0

斜率优化DP

BZOj题目传送门
洛谷题目传送门

S[i]=ij=1x[i]
易得出转移方程f[i]=max(f[j]+a(S[i]S[j])2+b(S[i]S[j])+c)

考虑斜率优化
x<y且x优于y

f[x]+a(S[i]S[x])2+b(S[i]S[x])+c>f[y]+a(S[i]S[y])2+b(S[i]S[y])+c

f[x]+a(S[i]22S[i]S[x]+S[x]2)+bS[i]bS[x]>f[y]+a(S[i]22S[i]S[y]+S[y]2)+bS[i]bS[y]

f[x]2aS[i]S[x]+aS[x]2bS[x]>f[y]2aS[i]S[y]+aS[y]2bS[y]

f[x]f[y]+aS[x]2bS[x]aS[y]2+bS[y]>2aS[i](S[x]S[y])

f[x]f[y]+a(S[x]2S[y]2)b(S[x]S[y])2a(S[x]S[y])>S[i]

然后就好了

代码:

#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 1000000
using namespace std;
typedef long long LL;
int n,r,w,que[MAXN+5];
LL f[MAXN+5],a,b,c,s[MAXN+5];
inline char readc(){
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF; return *l++;
}
inline LL _read(){
    LL num=0,flag=1; char ch=readc();
    while (!isdigit(ch)&&ch!='-') ch=readc();
    if (ch=='-') flag=-1,ch=readc();
    while (isdigit(ch)) { num=num*10+ch-48; ch=readc(); }
    return num*flag;
}
#define sqr(x) ((x)*(x))
inline LL K(int x,int y){
    return (f[x]-f[y]+a*(sqr(s[x])-sqr(s[y]))-b*(s[x]-s[y]))/(2*a*(s[x]-s[y]));
}
int main(){
    n=_read();
    a=_read(),b=_read(),c=_read();
    for (int i=1;i<=n;i++)
        s[i]=_read(),s[i]+=s[i-1],f[i]=1e18;
    for (int i=1;i<=n;i++){
        while (r<w&&K(que[r],que[r+1])<s[i]) r++;
        f[i]=f[que[r]]+a*sqr(s[i]-s[que[r]])+b*(s[i]-s[que[r]])+c;
        while (r<w&&K(que[w-1],que[w])>=K(que[w],i)) w--;
        que[++w]=i;
    }
    return printf("%lld\n",f[n]),0;
}
作者:a1799342217 发表于2017/11/10 11:51:16 原文链接
阅读:4 评论:0 查看评论

BZOJ3573 [Hnoi2014]米特运输

$
0
0

标签:LCA,

Description

米特是D星球上一种非常神秘的物质,蕴含着巨大的能量。在以米特为主要能源的D星上,这种米特能源的运输和储

存一直是一个大问题。D星上有N个城市,我们将其顺序编号为1到N,1号城市为首都。这N个城市由N-1条单向高速

通道连接起来,构成一棵以1号城市(首部)为根的树,高速通道的方向由树中的儿子指向父亲。树按深度分层:

根结点深度为0,属于第1层;根结点的子节点深度为1,属于第2层;依此类推,深度为i的结点属于第i+l层。建好

高速通道之后,D星人开始考虑如何具体地储存和传输米特资源。由于发展程度不同,每个城市储存米特的能力不

尽相同,其中第i个城市建有一个容量为A[i]的米特储存器。这个米特储存器除了具有储存的功能,还具有自动收

集米特的能力。如果到了晚上六点,有某个储存器处于未满的状态,它就会自动收集大气中蕴含的米特能源,在早

上六点之前就能收集满;但是,只有在储存器完全空的状态下启动自动收集程序才是安全的,未满而又非空时启动

可能有安全隐患。早上六点到七点间,根节点城市(1号城市)会将其储存器里的米特消耗殆尽。根节点不会自动

搜集米特,它只接受子节点传输来的米特。早上七点,城市之间启动米特传输过程,传输过程逐层递进:先是第2

层节点城市向第1层(根节点城市,即1号城市)传输,直到第1层的储存器满或第2层的储存器全为空;然后是第3

层向第2层传输,直到对于第2层的每个节点,其储存器满或其予节点(位于第3层)的储存器全为空;依此类推,

直到最后一层传输完成。传输过程一定会在晚上六点前完成。

由于技术原因,运输方案需要满足以下条件:

(1)不能让某个储存器到了晚上六点传输结束时还处于非空但又未满的状态,这个时候储存器仍然会启动自动收集

米特的程序,而给已经储存有米特的储存器启动收集程序可能导致危险,也就是说要让储存器到了晚上六点时要么

空要么满;

(2)关于首都——即1号城市的特殊情况,  每天早上六点到七点间1号城市中的米特储存器里的米特会自动被消耗

殆尽,即运输方案不需要考虑首都的米特怎么运走;

(3)除了1号城市,每个节点必须在其子节点城市向它运输米特之前将这座城市的米特储存器中原本存有的米特全部

运出去给父节点,不允许储存器中残存的米特与外来的米特发生混合;

(4)运向某一个城市的若干个来源的米特数量必须完全相同,不然,这些来源不同的米特按不同比例混合之后可能

发生危险。

现在D星人已经建立好高速通道,每个城市也有了一定储存容量的米特储存器。为了满足上面的限制条件,可能需

要重建一些城市中的米特储存器。你可以,也只能,将某一座城市(包括首都)中屎来存在的米特储存器摧毁,再

新建一座任意容量的新的米特储存器,其容量可以是小数(在输入数据中,储存器原始容量是正整数,但重建后可

以是小数),不能是负数或零,使得需要被重建的米特储存器的数目尽量少。

Input

第一行是一个正整数N,表示城市的数目。接下来N行,每行一个正整数,其中的第i行表示第i个城市原来存在的米

特储存器的容量。再接下来是N-I行,每行两个正整数a,b表示城市b到城市a有一条高速通道(a≠b)。

N<500000,A[j]<10^8

Output

输出文件仅包含一行,一个整数,表示最少的被重建(即修改储存器容量)的米特储存器的数目。

Sample Input

5

5

4

3

2

1

1 2

1 3

2 4

2 5

Sample Output

3

HINT

【样例解释】

  一个最优解是将A[1]改成8,A[3]改成4,A[5]改成2。这样,2和3运给1的量相等,4和5运给2的量相等,且每天晚上六点的时候,1,2满,3,4,5空,满足所有限制条件。

分析:

确定了一个节点的权值之后,其他节点的权值都能随之确定

所以计算出每个节点对应的根节点,排个序,乱搞,答案是同一个值出现次数的最大值

因为可能出现数字过大的情况,所以我们对所有数取对数

zz的我还把边表写错了qwq,自己太弱

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mem(x,num) memset(x,num,sizeof x)
#define eps 1e-8
#ifdef WIN32
#define LL "%I64d\n"
#else
#define LL "%lld\n"
#endif
using namespace std;
inline ll read()
{
	ll f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
const int maxn=5e5+6;
double val[maxn],s[maxn],a[maxn];
int d[maxn],n,ans=0,tmp=1,last[maxn],cnt=0;
struct edge{int to,next;}e[maxn<<1];
void dfs(int x,int fa){
#define reg(x) for(int i=last[x];i;i=e[i].next)
#define v e[i].to
    reg(x){
    	if(v==fa)continue;
    	s[v]=s[x]+log(d[x]);
    	dfs(v,x);
    }
}
int main()
{
	n=read();
	rep(i,1,n)a[i]=read();
	rep(i,1,n-1){
		int x=read(),y=read();
		e[++cnt]=(edge){x,last[y]};last[y]=cnt;
		e[++cnt]=(edge){y,last[x]};last[x]=cnt;
	    d[x]++,d[y]++;
	}
	rep(i,2,n)d[i]--;
	s[1]=log(1);
	dfs(1,0);
	rep(i,1,n)val[i]=s[i]+log(a[i]);
	sort(val+1,val+1+n);
	rep(i,2,n)
		if(abs(val[i]-val[i-1])<eps)tmp++;
		else ans=max(ans,tmp),tmp=1;
	ans=max(ans,tmp);
	cout<<n-ans<<endl;
	return 0;
}



作者:qwerty1125 发表于2017/11/10 11:52:15 原文链接
阅读:0 评论:0 查看评论

【最新版】从零开始在 macOS 上配置 Lua 开发环境

$
0
0

脚本语言,你可能更需要的是 Lua

不同的脚本语言有不同的特性,第一接触的脚本语言,可能会影响自己对整个脚本语言的理解和认知。我以前接触最多的脚本语言是 JavaScript。后果就是:我一度以为脚本语言都是必须和宿主语言运行在不同的进程;脚本本身的语法受环境的影响很大,很难做到统一;如果想统一写法,都需要在应用体积上做出非常大的妥协(嵌入一个通用的 JS 解释器,会使应用体积增大十几 M)。

我在试着做一些努力,去改进因大量使用 JavaScript 引起的一些特定的技术问题。但是偶然间又想起了 Lua。最开始是从玩 WOW 的室友那里听说 Lua 的。因为他说写WOW插件很赚钱,所以曾经认真地搜索过 Lua,现在脑海中有一些残留的片段。

我突然意识到,可能 JavaScript 的大部分限制,在 Lua 或其他脚本语言中并不存在。想要解决那些因为使用 JavaScript 引起的各种问题,可能只需要换一门脚本语言。

当然,此处不考虑通常意义上的使用难度,学习难度,推广成本一类的因素;毕竟我是纯自嗨。但假如,Lua 真的能很好解决我目前遇到的脚本语言无法和宿主语言灵活通信的问题,必将给自己的整体知识体系带来一个新的提升,也必将在自己的日常实践中创造出许多新的可能。

所涉及的各个工具的版本

  • 编程语言: Lua 5.3.4

  • Lua 模块管理工具:LuaRocks 2.3.0

  • 编辑器:IntelliJ IDEA CE (社区版)

Build #IC-172.4343.14, built on September 26, 2017
JRE: 1.8.0_152-release-915-b12 x86_64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Mac OS X 10.13.1

  • 调试插件:EmmyLua 1.2.0

  • 操作系统:macOS 10.13.1

  • macOS 专用模块管理工具: Homebrew 1.3.6

以下讨论,均以 macOS 为主,其他系统平台仅供参考。

安装 Lua

打开 macOS 终端,输入以下指令:

brew tap homebrew/versions
brew install lua53

Lua 的安装有多种方式,这是较为简化高效的一种。需要注意的是,以此种方式安装,Lua 的调用命令,将变为 lua5.3

Lua 安装成功

安装 Lua 模块管理工具:LuaRocks

打开 macOS 终端,输入以下指令:

brew tap mesca/luarocks
brew install luarocks53

LuaRocks 的安装也有多种方式,这是较为简化高效的一种。需要注意的是,以此种方式安装,LuaRocks 的调用命令,将变为 luarocks-5.3

LuaRocks 安装成功

选择一个合适的 Lua 编辑器: IntelliJ IDEA CE

Lua 日常编码,推荐使用 IntelliJ IDEA CE(社区免费版),下载地址:https://www.jetbrains.com/idea/download/

主要是从配置难度,语法高亮,代码提示,代码调试等方面权衡。

IntelliJ IDEA CE 预览

使用 EmmyLua 插件配置调试环境

安装 EmmyLua

Lua 的调试和高亮,主要得益于 EmmyLua。在 IntelliJ IDEA CE 的 Plugins 中,直接搜索安装即可。记得,要先安装此插件,然后再新建工程。安装此插件后,工程模板,会多一个 Lua 模板选项。从 Lua 模板新建工程,会简化许多 Lua 相关的配置。

安装 EmmyLua

安装 luasocket

在安装 EmmyLua 插件之后,还需要安装一个 Lua 库 luasocket,才能进行调试。

打开终端,输入以下指令:

sudo luarocks-5.3 install luasocket  

修改 lua 路径配置

Lua 的配置路径要从默认的 lua,改为 lua5.3 的真实路径,一般是 /usr/local/bin/lua5.3

配置 Lua

开始调试

在 IntelliJ IDEA CE 中新建 Lua 工程,然后新建 Lua 文件 hello.lua,输入代码:

-- defines a factorial function
function fact (n)
    if n == 0 then
        return 1
    else
        return n * fact(n - 1)
    end end
a = 42
print(fact(a))

在编辑区左侧,打上几个断点,然后文件编辑区右键,选择 Debug ‘hello.lua’:

debug 右键菜单

一起简单看下 Debug 断点调试的效果:

debug 效果演示

注意事项

  • 一定是要在配置好 EmmyLua 插件后,直接基于新出现的 Lua 模板新建工程;否则在修改项目配置上,可能会花费许多时间。

  • 只有 Lua 5.3 以后的版本才支持 UTF-8,有大量中文处理需求的童鞋可能会需要这个信息。

  • 调试时报错 module ‘socket’ not found ,是因为没有安装 luasocket。

  • Lua 基于MIT 开源,如果哪天想自己定义某种新语言来实现特定的产品特性,可以考虑基于 Lua 定制。

  • 借助于 LuaJIT,Lua 的执行效率可以进一步提升几十倍。

  • Lua 支持各种低级硬件嵌入式开发,可移植性非常好,物联网时代可能会有新的可能和增长潜力。

  • 如果感觉 lua5.3 没有 lua 写着方便,可以试着在 .profile 中配置 alias 命令别名,详见:https://stackoverflow.com/a/8967864

alias lua="/usr/local/bin/lua5.3"
alias luarocks="/usr/local/bin/luarocks-5.3"
  • 命令别名,不能 sudo 执行,如安装 luasocket 时,还是需要 sudo 原始命令:

sudo luarocks-5.3 install luasocket

小结

以上介绍了 macOS 平台,Lua 从安装到配置调试环境的完整过程。接下来,就可以根据自己的节奏和需要,好好领略 Lua 之美了~

参考文档:

作者:sinat_30800357 发表于2017/11/10 12:32:58 原文链接
阅读:0 评论:0 查看评论

Leetcode--Binary Tree Inorder Traversal

$
0
0

Given a binary tree, return the inorder traversal of its nodes’ values.

For example:
Given binary tree [1,null,2,3],
1
\
2
/
3
return [1,3,2].

Note: Recursive solution is trivial, could you do it iteratively?

思路:二叉树中序遍历。

方法一:递归。左中右顺序深度优先搜索。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>res;
        inorder(root,res);
        return res;
    }
    void inorder(TreeNode* root,vector<int>&res){
        if(root){
            inorder(root->left,res);
            res.push_back(root->val);
            inorder(root->right,res);
        }
    }
};

方法二:非递归。堆栈循环,如果左子树有元素就先遍历左子树,然后返回根节点输出,再遍历右子树。堆栈中维护未打印的根节点信息。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>res;
        stack<TreeNode*>s;
        TreeNode *p=root;
        while(p||!s.empty()){
            if(p){
                s.push(p);
                p=p->left;
            }
            else{
                p=s.top();
                s.pop();
                res.push_back(p->val);
                p=p->right;
            }
        }
        return res;
    }
};
作者:qq_20791919 发表于2017/11/10 12:40:24 原文链接
阅读:1 评论:0 查看评论

nginx源码阅读(十三).新建连接并处理就绪事件

$
0
0

前言

本小节主要讨论事件模块中如何接受新连接,其中涉及到了惊群以及负载均衡的处理。

如何建立新连接

之前在分析ngx_event_process_init函数时,将所有空闲连接形成链表之后,它会遍历所有监听端口并将其读事件的回调函数设置为ngx_event_accept

接着会把监听连接的读事件添加到ngx_epoll_module模块中。当执行ngx_epoll_process_events时,如果有新连接事件出现,则会调用ngx_event_accept来建立新的连接。

建立新连接的回调函数

建立新连接的回调函数是ngx_event_accept,每个监听连接的读事件的handler都在ngx_event_process_init中设置为ngx_event_accept
下面直接看它的源码(省略了不必要的部分):

void
ngx_event_accept(ngx_event_t *ev)
{
    socklen_t          socklen;
    ngx_err_t          err;
    ngx_log_t         *log;
    ngx_socket_t       s;
    ngx_event_t       *rev, *wev;
    ngx_listening_t   *ls;
    ngx_connection_t  *c, *lc;
    ngx_event_conf_t  *ecf;
    u_char             sa[NGX_SOCKADDRLEN];
    ......

    //获取ngx_event_core_module模块的配置项结构体指针
    ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);

    if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
        ev->available = 1;

    } else if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) {
        ev->available = ecf->multi_accept;
    }

    lc = ev->data;
    ls = lc->listening;
    ev->ready = 0;

    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                   "accept on %V, ready: %d", &ls->addr_text, ev->available);

    /* 这个循环以available标志位作为判断条件
     * 当该标志位被置1,则代表每次尽可能的多建立新连接
     * 否则每次调用ngx_event_accept只建立一个新连接
     */
    do {           
        socklen = NGX_SOCKADDRLEN;
        ......
        //调用accept接受新连接
        s = accept(lc->fd, (struct sockaddr *) sa, &socklen);


        if (s == -1) {
            err = ngx_socket_errno;

            if (err == NGX_EAGAIN) {
                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
                               "accept() not ready");
                return;
            }


            ngx_log_error((ngx_uint_t) ((err == NGX_ECONNABORTED) ?
                                             NGX_LOG_ERR : NGX_LOG_ALERT),
                          ev->log, err, "accept() failed");

            if (err == NGX_ECONNABORTED) {
                if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
                    ev->available--;
                }

                if (ev->available) {
                    continue;
                }
            }

            return;
        }
        .....

        /* 这一步操作是设置负载均衡的阀值
         * ngx_accept_disabled的初值是负数,为总连接的7/8
         * 当ngx_accept_disabled为负数时,
         * 则不会触发负载均衡的操作
         * 当ngx_accept_disabled是正数时,就会触发负载均衡的操作了(当前进程不会处理新连接,而是将ngx_accept_disabled减1)
         */
        ngx_accept_disabled =  ngx_cycle->connection_n / 8
                              - ngx_cycle->free_connection_n;

        //获取一个空闲连接
        c = ngx_get_connection(s, ev->log);

        if (c == NULL) {
            if (ngx_close_socket(s) == -1) {
                ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                              ngx_close_socket_n " failed");
            }

            return;
        }

        ......

        //每个连接都有其一个专属的内存池
        c->pool = ngx_create_pool(ls->pool_size, ev->log);
        if (c->pool == NULL) {
            ngx_close_accepted_connection(c);
            return;
        }

        c->sockaddr = ngx_palloc(c->pool, socklen);
        if (c->sockaddr == NULL) {
            ngx_close_accepted_connection(c);
            return;
        }

        ngx_memcpy(c->sockaddr, sa, socklen);

        log = ngx_palloc(c->pool, sizeof(ngx_log_t));
        if (log == NULL) {
            ngx_close_accepted_connection(c);
            return;
        }

        /* set a blocking mode for aio and non-blocking mode for others */

        /* 设置套接字的属性 */
        if (ngx_inherited_nonblocking) {
            if (ngx_event_flags & NGX_USE_AIO_EVENT) {
                if (ngx_blocking(s) == -1) {
                    ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                  ngx_blocking_n " failed");
                    ngx_close_accepted_connection(c);
                    return;
                }
            }

        } else {
            if (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) {
                if (ngx_nonblocking(s) == -1) {
                    ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                  ngx_nonblocking_n " failed");
                    ngx_close_accepted_connection(c);
                    return;
                }
            }
        }

        *log = ls->log;

        /* 接下来设置连接的成员值 */

        //设置接受、发送字符流的方法
        c->recv = ngx_recv;
        c->send = ngx_send;
        c->recv_chain = ngx_recv_chain;
        c->send_chain = ngx_send_chain;

        c->log = log;
        c->pool->log = log;

        c->socklen = socklen;
        c->listening = ls;
        c->local_sockaddr = ls->sockaddr;

        c->unexpected_eof = 1;

#if (NGX_HAVE_UNIX_DOMAIN)
        if (c->sockaddr->sa_family == AF_UNIX) {
            c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
            c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
            ......
        }
#endif

        rev = c->read;
        wev = c->write;

        wev->ready = 1;

        if (ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT)) {
            /* rtsig, aio, iocp */
            rev->ready = 1;
        }

        if (ev->deferred_accept) {
            rev->ready = 1;
#if (NGX_HAVE_KQUEUE)
            rev->available = 1;
#endif
        }

        rev->log = log;
        wev->log = log;

        /*
         * TODO: MT: - ngx_atomic_fetch_add()
         *             or protection by critical section or light mutex
         *
         * TODO: MP: - allocated in a shared memory
         *           - ngx_atomic_fetch_add()
         *             or protection by critical section or light mutex
         */

        c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);

        ......

        if (ls->addr_ntop) {
            c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len);
            if (c->addr_text.data == NULL) {
                ngx_close_accepted_connection(c);
                return;
            }

            c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->addr_text.data,
                                             ls->addr_text_max_len, 0);
            if (c->addr_text.len == 0) {
                ngx_close_accepted_connection(c);
                return;
            }
        }

......

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
                       "*%d accept: %V fd:%d", c->number, &c->addr_text, s);
                       if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {

            /* 将该连接对应的读和写事件都添加到epoll监听中*/
            if (ngx_add_conn(c) == NGX_ERROR) {
                ngx_close_accepted_connection(c);
                return;
            }
        }

        log->data = NULL;
        log->handler = NULL;

        //调用监听端口上的ngx_listening_t结构体的handler方法处理新连接
        ls->handler(c);

        if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
            ev->available--;
        }

    } while (ev->available);
}

本来想画一个大致的流程图,不过发现《深入理解Nginx》中已经归纳的很好了,如图:
这里写图片描述

处理事件

之前分析ngx_epoll_module时,process_events对应的ngx_epoll_process_events函数还没有分析,放在这里比较合适,它用于处理事件,其中就调用了ngx_event_accept函数建立新连接。

这里也会详细说明关于如何跳过过期的事件。关于过期事件,是指调用epoll_wait返回的就绪的事件中包含一个连接上的多个事件,在处理前面的事件时关闭了该连接,这样就会导致该连接上后面的事件过期失效。

前面的事件关闭了连接之后,将fd置为-1,然后再归还到连接池中,这样可以解决大多数过期事件的问题。但是由于内核分配描述符是从小到大依次分配的,因此如果关闭了连接之后,下一个事件新建连接,复用了刚释放的连接,同时获得的描述符也是刚归回的描述符。这样就导致原本过期的事件对应的是新建立的连接,它会以为自己并没有过期,但是其实它对应的应该是已经关闭的连接,已经过期了。

关于这种特殊情况,nginx采用的处理方法是,利用ngx_event_t中的instance位,当重复使用连接的时候,就将该连接对应的该位取反,这样早期获得该连接的instance位,与马上重用该连接对应instance就不相同了。关于如何存储早期的instance位是一个问题,我们可以额外增加1位来专门存储它,不过nginx有更好的办法,没有增加额外的成本,等下我们就可以看到这是如何做到的。

其实大部分超时事件可以通过该连接对应的fd置为-1解决,但是刚才的特殊情况,是重用了刚释放的连接并且内核分配的描述符又恰好与原来的连接对应的描述符一样。造成这种特殊情况有比较坎坷的要求,首先是需要重用同一个连接,其次是该连接对应的描述符要与原来连接对应的描述符相等,将instance位置反,就是专门为了处理这种特殊情况。

static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
    int                events;
    uint32_t           revents;
    ngx_int_t          instance, i;
    ngx_uint_t         level;
    ngx_err_t          err;
    ngx_event_t       *rev, *wev, **queue;
    ngx_connection_t  *c;

    /* NGX_TIMER_INFINITE == INFTIM */

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "epoll timer: %M", timer);
    //若设置了timer_resolution,timer则设置为-1
    //这是为了防止长时间没有激活的事件导致阻塞在epoll_wait上
    //进而导致ngx_time_update得不到调用,以至时间的精度缺失
    events = epoll_wait(ep, event_list, (int) nevents, timer);

    err = (events == -1) ? ngx_errno : 0;
    //若NGX_UPDATE_TIME置位或者ngx_event_timer_alarm置位,则调用ngx_time_update更新时间缓存
    //setitimer设置每过timer_resolution毫秒调用一次ngx_timer_signal_handler方法,将ngx_event_timer_alarm设置为1
    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
        ngx_time_update();
    }

    if (err) {
        if (err == NGX_EINTR) {

            if (ngx_event_timer_alarm) {
                ngx_event_timer_alarm = 0;
                return NGX_OK;
            }

            level = NGX_LOG_INFO;

        } else {
            level = NGX_LOG_ALERT;
        }

        ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
        return NGX_ERROR;
    }

    if (events == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "epoll_wait() returned no events without timeout");
        return NGX_ERROR;
    }

    ngx_mutex_lock(ngx_posted_events_mutex);

    //处理就绪的事件
    for (i = 0; i < events; i++) {
        /* 这几行代码解决了过期事件问题
         * ngx_event_t中有个标志位instance,用它即可判断事件是否过期
         * 主要是利用了内存中地址对齐从而指针指向的变量地址的最后一位永远为0
         * 这样我们就可以通过最后一位来存储原连接的instance
         * 然后通过与该连接的读事件的instance标志位相与就可以判断是否过期
         */

        //获取到对应的连接
        c = event_list[i].data.ptr;

        //取得instance位
        instance = (uintptr_t) c & 1;
        //还原为正确的连接地址
        c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);

        rev = c->read;

        //判断是否为过期事件,若是则退出本次的处理
        if (c->fd == -1 || rev->instance != instance) {

            /*
             * the stale event from a file descriptor
             * that was just closed in this iteration
             */

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "epoll: stale event %p", c);
            continue;
        }

        revents = event_list[i].events;

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "epoll: fd:%d ev:%04XD d:%p",
                       c->fd, revents, event_list[i].data.ptr);

        if (revents & (EPOLLERR|EPOLLHUP)) {
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "epoll_wait() error on fd:%d ev:%04XD",
                           c->fd, revents);
        }

#if 0
        if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "strange epoll_wait() events fd:%d ev:%04XD",
                          c->fd, revents);
        }
#endif

        if ((revents & (EPOLLERR|EPOLLHUP))
             && (revents & (EPOLLIN|EPOLLOUT)) == 0)
        {
            /*
             * if the error events were returned without EPOLLIN or EPOLLOUT,
             * then add these flags to handle the events at least in one
             * active handler
             */

            revents |= EPOLLIN|EPOLLOUT;
        }

        //当前事件是读事件,并且该事件是活跃的
        if ((revents & EPOLLIN) && rev->active) {

            if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
                rev->posted_ready = 1;

            } else {
                rev->ready = 1;
            }

            /* 若延迟处理的标识位置位,则将事件添加到相应的队列中
             * 新连接事件添加到ngx_posted_accept_events队列中
             * 普通的事件添加到ngx_posted_events队列中
             * 如果并不需要延时处理,则直接回调该事件的处理方法
             * 至于为什么需要延迟处理,这是为了配合解决惊群和负载均衡问题,我们放在下一节讲
             */
            if (flags & NGX_POST_EVENTS) {
                queue = (ngx_event_t **) (rev->accept ?
                               &ngx_posted_accept_events : &ngx_posted_events);

                ngx_locked_post_event(rev, queue);

            } else {
                //这里的handler则可能是ngx_event_accept函数,建立新连接
                rev->handler(rev);
            }
        }
        //获取写事件
        wev = c->write;

        //当前是写事件并且该事件为活跃事件
        if ((revents & EPOLLOUT) && wev->active) {

            //判断事件是否过期
            if (c->fd == -1 || wev->instance != instance) {

                /*
                 * the stale event from a file descriptor
                 * that was just closed in this iteration
                 */

                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "epoll: stale event %p", c);
                continue;
            }

            if (flags & NGX_POST_THREAD_EVENTS) {
                wev->posted_ready = 1;

            } else {
                wev->ready = 1;
            }
            //延迟处理
            if (flags & NGX_POST_EVENTS) {
                //将写事件添加到ngx_posted_events队列中
                ngx_locked_post_event(wev, &ngx_posted_events);

            } else {
                //调用回调函数
                wev->handler(wev);
            }
        }
    }
    //解锁
    ngx_mutex_unlock(ngx_posted_events_mutex);

    return NGX_OK;
}

ngx_epoll_process_events的主要工作就是调用epoll_wait,处理激活的事件,并检测事件是否过期,过期则不处理,接着判断该事件是否需要延迟处理,如果需要,则加到相应的队列中,否则调用连接上对应的读/写事件的回调函数进行处理。

小结

本小节主要分析了新连接的处理以及ngx_epoll_process_events函数、过期事件的处理。接下来,我们将看到nginx是如何处理惊群以及负载均衡问题以及整个事件处理的流程。

作者:Move_now 发表于2017/11/9 22:12:01 原文链接
阅读:19 评论:0 查看评论

LeetCode-621:Task Scheduler (任务调度) -- medium

$
0
0

Question

Given a char array representing tasks CPU need to do. It contains capital letters A to Z where different letters represent different tasks.Tasks could be done without original order. Each task could be done in one interval. For each interval, CPU could finish one task or just be idle.

However, there is a non-negative cooling interval n that means between two same tasks, there must be at least n intervals that CPU are doing different tasks or just be idle.

You need to return the least number of intervals the CPU will take to finish all the given tasks.

Example 1:

Input: tasks = [“A”,”A”,”A”,”B”,”B”,”B”], n = 2
Output: 8
Explanation: A -> B -> idle -> A -> B -> idle -> A -> B.

Note:

  • The number of tasks is in the range [1, 10000].
  • The integer n is in the range [0, 100].

问题解析:

给定一个表示CPU需要做的任务的字符数组。它包含大写字母A到Z,其中不同的字母表示不同的任务。任务完成顺序不限。每个任务可以在一个时间内完成,对于每个时间,CPU可以完成一个任务或空闲。

但是,在两个相同的任务之间有一个冷却时间间隔n,即两个相同任务之间至少必须有n个冷却时间间隔,其中的间隔内CPU可以执行其他不同的任务或是处于空闲状态。

返回CPU完成所有给定任务所需的最小时间

Answer

Solution 1:

寻找调度规律。

  • 从举例子中我们可以得出任务调度的规律。
  • 如给定:AAABBCD,n=2。那么我们满足个数最多的任务所需的数量,即可以满足任务间隔要求,即:AXXAXXA;(其中,X表示需要填充任务或者idle的间隔)
  • 如果有两种或两种以上的任务具有相同的最多的任务数,如:AAAABBBBCCDE,n=3。那么我们将具有相同个数的任务A和B视为一个任务对,最终满足要求的分配为:ABXXABXXABXXAB,剩余的任务在不违背要求间隔的情况下穿插进间隔位置即可,空缺位置补idle。
  • 由上面的分析我们可以得到最终需要最少的任务时间:(最多任务数-1)*(n + 1) + (相同最多任务的任务个数)。
  • 有上面的例子来说就是:(num(A)-1) * (3+1) + (2)。
class Solution {
    public int leastInterval(char[] tasks, int n) {
        int[] c = new int[26];

        for (char t : tasks){
            c[t - 'A']++;
        }
        Arrays.sort(c);

        int i = 25;
        while (i >= 0 && c[i] == c[25]) i--;

        return Math.max(tasks.length, (c[25]-1) * (n+1) + (25-i));
    }
}
  • 时间复杂度:O(n),空间复杂度:O(1)
作者:Koala_Tree 发表于2017/11/10 12:47:06 原文链接
阅读:61 评论:0 查看评论

spring boot shiro视频

$
0
0

【视频

à Spring Boot实战篇之Shiro

http://study.163.com/course/introduction.htm?courseId=1004523002

 

 

====================================================

Spring   Boot    Shiro 视频实战篇

===================================================

 

1. 适合人群

有Spring Boot基础的人群。

 

2.使用技术

(1)spring boot(整合框架)

(2)spring mvc

(3)spring data jpa(持久化操作)

(4)shiro(安全框架)

(5)thymeleaf(模板引擎)

(6)ehcache(缓存管理)

(7)mysql(数据库)

(8)js/css/img(静态资源使用)

(9)kaptcha(验证码库)

(10)MyBatis注解方式

 

3.源码说明

(1)Spring Boot+Shiro+JPA : 使用Spring Boot框架,身份权限使用Shiro,持久层使用Spring Data JPA;

(2)Spring Boot+Shiro+MyBatis : 使用Spring Boot框架,身份权限使用Shiro,持久层使用MyBatis (注解方式);

 

4.课程目录

1. Spring Boot Shiro介绍

 

2. Spring Boot 搭建无Shiro的框架

 

3. Spring Boot Shiro拦截

 

4. Spring Boot Shiro身份认证准备工作

 

5. Spring Boot Shiro身份认证

 

6. Spring Boot Shiro权限控制

 

7. Spring Boot Shiro缓存

 

8. Spring Boot Shiro记住密码

 

9. Spring Boot Shiro登录成功之后下载favicon.ico

 

10. Spring Boot 在thymeleaf使用shiro标签

 

11. Spring Boot Shiro密码加密算法

 

12.Spring Boot Shiro使用JS-CSS-IMG

 

13. Spring Boot Shiro限制登录尝试次数

 

14.Spring Boot Shiro 验证码

 

 

Spring Boot Shiro无状态Web

 

1. Spring Boot之Shiro无状态:构建一个简单MVC

 

2. Spring Boot之Shiro无状态:搭建无状态

 

3. Spring Boot之Shiro无状态:请求控制拦截

作者:linxingliang 发表于2017/11/10 12:54:30 原文链接
阅读:33 评论:0 查看评论

CSDN 博客 修改文章搜索为 bing 搜索,且只搜索自己的博客的方法

$
0
0

CSDN 博客 修改文章搜索为 bing 搜索,且只搜索自己的博客的方法

csdn 自带的博客搜索调用的百度的代码,但是搜索效果很不理想,而且默认为全站搜索。

在我们的博客里面进行搜索的大多数人,都应该是希望只搜索当前博客的。所以我就写了一段代码,来实现这个功能。

首先,你必须是博客专家,有插入 html 的权限。

插入自定义组件

CSDN 的博客专家允许插入自定义的 html 代码。但是我尝试了一下,不能直接执行 js 代码,否则这个功能的实现就是一件非常简单的事情了。

由于不能执行 js 代码,我只能另辟蹊径,用一个 form 将关键词传出去,然后在我自己的网站里面接收这个关键词,并进行搜索工作。

如何插入自定义组件不谈,只说插入代码如下:

<div class="search-bing">
  <form action="http://www.fengcms.com/blogsearch.php" method="get" target="_blank">
    <input class="bing-keyword" name="keyword" type="text" placeholder="请输入关键词">
    <input class="bing-submit" type="submit" value="搜索">
  </form>
</div>
<style>
  .search-bing {position: relative;height: 40px;}
  .bing-keyword,.bing-submit {
    display: block;border: 1px solid;box-sizing: border-box;height: 40px;padding: 5px;border-radius: 0;outline: none;
  }
  .bing-keyword {
    width: 100%;border-color: #ddd;
  }
  .bing-keyword:focus {
    border-color: #20A0FF;
  }
  .bing-submit {
    position: absolute; width: 50px;right: 0;top: 0;font-size: 14px;cursor: pointer;background: #20A0FF;color: #fff;border-color: #20A0FF;
  }
  .bing-submit:hover,.bing-submit:focus {
    background: #1D8CE0;border-color: #1D8CE0;
  }
</style>

代码没什么特殊的,只是一个普通表单。另外加上一点样式而已。

关键词处理程序

如上代码,表单会把关键词传送给 http://www.fengcms.com/blogsearch.php 这个地址。然后我这里如何处理呢,请看代码如下:

<?php
$url = "https://cn.bing.com/search?q=site%3Ablog.csdn.net%2Ffungleo+".$_GET["keyword"];
echo "<script>";
echo "window.location.href='$url'";
echo "</script>";
?>

代码非常简单,通过 $_GET 获取关键词参数,与 bing 搜索的地址拼接,然后通过 js 跳转走,就好了。

由于我不会 php 所以用了 js 的跳转方式。可能直接写 php 会更短。

这篇博文对于大多数人都没啥用。大多数 CSDN 的博主可能都会自己弄。算了,写给我自己看吧。

本文由 FungLeo 原创,允许转载,但转载必须保留首发链接。

作者:FungLeo 发表于2017/11/10 14:09:25 原文链接
阅读:0 评论:0 查看评论

git: non-fast-forward errors

$
0
0

遇到的问题

$ git push origin master
Username for 'https://github.com': UserName
Password for 'https://UserName@github.com': 
To https://github.com/UserName/tool.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'https://github.com/UserName/tool.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

于是我试了 git pull ,跳出来让我 set up-stream ,set 完依然报错。

经过上网查阅,在 help.github.com 上找到了解决方案:

这里写图片描述

该方案解决了我遇到的 non-fast-forward errors 问题。

实验代码

$ git push origin master
Username for 'https://github.com': UserName
Password for 'https://UserName@github.com': 
To https://github.com/UserName/tool.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'https://github.com/UserName/tool.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

$ git pull origin master
From https://github.com/UserName/tool
 * branch            master     -> FETCH_HEAD
Merge made by the 'recursive' strategy.
 README.md | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

$ git push origin master
Username for 'https://github.com': UserName
Password for 'https://UserName@github.com': 
Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 700 bytes | 0 bytes/s, done.
Total 5 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To https://github.com/UserName/tool.git
   0e079c8..98a504b  master -> master

$  


作者:JNingWei 发表于2017/11/9 23:11:52 原文链接
阅读:39 评论:0 查看评论

曾经的 Java IDE 王者 Eclipse 真的没落了?21 款插件让它强大起来!

$
0
0

俗话说,好马配好鞍,才能展现千里马的实力。一名好的开发者,必定要有一套好的开发工具才能打造出最好的产品给用户。要论世界上最好用的 IDE 是哪一种?有人会选择老牌的 Visual Studio 或是 Eclipse;有人会选择一路飙升的 IntelliJ;也有人更偏爱 Google 发布的 Android Studio 等等。

每位开发者按照不同的需求及爱好有各自不同的选择。其中,对于老牌军 Ecplise 来说,众多开发者对其真的是又爱又厌倦。曾几何时,各种昂贵及少量的 IDE 出现,突然有这么一款免费且开源、速度相对更快、Google 支持、各种教科书推行的 IDE,想必不流行也难。但之后各种 IDE 的百花齐放, Ecplise 的卡顿、太大、复杂等弊端逐渐显现,开始走下坡路,一篇《曾经的 Java IDE 王者 Eclipse,它是如何没落的?》文章也对其趋势进行了解析:

  • Eclipse 4 的发布标志着 Eclipse 的没落,缓慢的运行速度、奇怪的问题以及丑陋的 UI ,让 Eclipse 好像一下倒退了好几年。
  • Equinox P2 项目的目的是让插件升级变得更简单,然而它最终却变得非常复杂,而且好像要和 InstallShield 竞争成为通用安装工具。由于这个原因,它最常用的功能——安装 Eclipse 插件——也不再好用了。
  • Intellij 社区版和免费的 Android Studio 出现意味着,对于寻求免费 IDE 的纯 Java 开发人员、学生和开源项目来说,可以有一个更好的 IDE,无须局限于 Ecplise。

虽说其发展趋势不如以前,但根据近几个月的 PYPL 指数来看,Eclipse 也依然保持受欢迎的 IDE 排行榜前三名,且据上个月最新的 PYPL 指数显示,Eclipse 以 24.93 % 的成绩击败了 Visual Studio ,夺下冠军宝座,再次成为最流行的 IDE。

之所以仍受广大开发者的喜爱,这在很大程度上归功于该平台所支持的强大而广泛的插件生态系统。起初它主要作为 Java 的开发工具,而如今越来越多的人将其用于其他编程语言和框架,从 Scala 和 Kotlin 到 JavaScript 和 Node.js。

多语言、多框架的支持得以实现源于 Eclipse 良好的插件体系结构。将大大小小的各种工具添加到你的 Eclipse 中,就可以扩展其功能并对其进行自定义从而满足你的特定开发需求。

下面将介绍多个对于开发者来说非常有用的 Eclipse 插件。这其中有的已流行多年,有的盛行不久,有的界面非常可爱,各种各样插件的存在使得 Eclipse 变得更加强大。

Darkest Dark

如果你也是那种讨厌白色背景的人,那么肯定不会问我为什么黑屏更好,也不会觉得使用“darkest”修改“dark”是多余的。我相信你一旦用了 Darkest Dark(https://marketplace.eclipse.org/content/darkest-dark-theme) 主题之后一定会爱上它,因为它让你面对一整天电脑屏幕之后的眼睛不那么难受。

SpotBugs

我个人非常喜欢 SpotBugs(https://marketplace.eclipse.org/content/spotbugs-eclipse-plugin) 这个工具。我借助它帮我找出我正在写的代码中的错误。与之前使用的 FindBugs 工具类似,SpotBugs 像一个严格的审计人员一样,其内部预编了数百个“bug 匹配模板”。它搜索你的代码,使用bug 模板进行匹配就可以帮助你找到代码中的错误。我相信有一些程序员会对 SpotBugs 工具找出的bug表示怀疑,但是有这么一个工具帮你找出错误,给你一定的参考总是好的。

Checkstyle

尽管有时候我像讨厌法西斯主义一样厌恶 Checkstyle(https://marketplace.eclipse.org/content/checkstyle-plug),但是我必须承认,在每个人都遵循相同规则并以同样的方式构建代码的项目工作会更加容易。大脑有一种学习风格的方式,当每个方法的空白处于同一个位置时,大脑就能更快地理解每个人的代码。当然,你可以编写 Checkstyle 插件来执行你自己所喜爱的规则,这意味着你可以自己动手定制自己独特的东西。

Subclipse 与 Subversive

如今在版本控制领域 Git 占据的份额越来越大,但是依然有很多人使用 Subversion 工具。对于 SVN 用户来说一般有两个工具可以选择:Subclipse(https://marketplace.eclipse.org/content/subclipse/)和 Subversive(https://marketplace.eclipse.org/content/subversive-svn-team-provider)。这两者都能很好地完成版本控制管理工作,目前它们各自的用户数几乎平分秋色。这两者的差异主要在于信息呈现方式有所不同。具体使用哪一个取决于个人喜好,不过据统计用户在使用这两个工具时都会偶尔遇到一些小问题。

M2Eclipse

M2Eclipse(https://marketplace.eclipse.org/content/maven-integration-eclipse-luna-and-newer),或者简称 M2E ,是将 Maven 构建工具集成到 Eclipse 的首选方案,这样一来,你的每次保存将触发 Maven 构建项目而不仅仅是 Eclipse。精心设计的 POM(项目对象模型)避免了需要记住 Maven 的 XML 模式的麻烦,当然,你依然可以编辑原始 XML。上图显示了各种代码的依赖关系。

Unnecessary Code Detector

当我们需要清理代码并删除那些不需要的代码碎片时,Unnecessary Code Detector(https://marketplace.eclipse.org/content/unnecessary-code-detector/metrics) 就可以完成这项工作。当你点击按钮该工具就会出现标志来告诉你哪些方法不再使用。此外,这个工具还会标记出其他的编码错误,在将代码提交到仓库之前使用该工具是非常有用的。

SonarLint

解决空格和 Tab 问题是很多程序员都要做的工作,lingting 工具可以帮助我们自动完成这项工作。SonarLint(https://marketplace.eclipse.org/content/sonarlint) 将 lint 的强大功能带到了 Eclipse 中。在检查代码之前,你可以长时间运行 lint 工具,其内部的代码审查机制将帮助你解决空格和 Tab 问题。

JRebel

调试代码从来都不是一件简单的事,如果你的代码构建非常复杂那么调试起来就更不容易了。JRebel(https://marketplace.eclipse.org/content/jrebel-eclipse) 是一个非常智能的 Java 代理,它可以更改代码并将其插入到已经运行的代码中。我一直以来都在使用 JRebel,它非常强大,在重建或者重新运行代码之前你可以尝试使用一下 JRebel。这对于 Eclipse 来说非常合适,因为 Eclipse 从一开始就已经完成了大部分的工作。

TestNG

为代码编写好的单元测试可能比编写代码本身更加重要。TestNG(https://marketplace.eclipse.org/content/testng-eclipse/) 将你的测试与 Eclipse 集成在一起,因此你可以很方便地运行它们。编译之后就产生结果,测试的集成度比以往更高。

JSweet

JSweet(https://github.com/cincheo/jsweet-eclipse-plugin) 可以将 Java 代码转换成 JavaScript 代码。对于那些想要从 Java 转到 JavaScript 的程序员来说可以继续编写Java 代码。如果你不想花太多精力敲代码,那么你可以使用 TypeScript ,当然最终都会转换为 JavaScript。Eclipse 的这款插件让你可以通过 Java 代码实现大部分的功能,然后在最后生成 JavaScript 即可。

Bytecode Outline

大部分程序员都没有契机去了解 Java 堆栈里面到底发生了什么。我们使用高级编程语言就可以实现想要的功能。但是当你想要深入挖掘内部机制试图让代码运行更快时,查看实际的 Java 字节码是非常有用的。如果你是一名真正的程序员,你肯定会对深层次的东西充满兴趣。Bytecode Outline(https://marketplace.eclipse.org/content/bytecode-outline) 正是开启代码灵魂窗口的工具。

PyDev

如果你对 Python 的普及程序有所怀疑,那么不妨看看 PyDev(https://marketplace.eclipse.org/content/pydev-python-ide-eclipse), 它是一个能够让 Python 开发者告别命令行并享受 Eclipse 的强大插件。它不仅支持基本语法,还支持流行的 Python 的框架,比如 Django, 它能够将 Django 代码推送到 Google App Engine。它对于 Python 开发者来说是一个完整的开发插件。

Nodeclipse

使用 JavaScript 构建服务器应用程序已经在无数程序员中风靡多时。如今,Nodeclipse(https://marketplace.eclipse.org/content/nodeclipse) 插件让开发者从带有奇怪参数标志以及无数脚本的命令行中解脱出来,取而代之的是非常友好、易用的高度集成化的开发环境。当然,你仍然可以通过命令行和 VI 编辑器编写 Node.js 代码,但是何必要花那么多的精力去记住大量的命令呢?

Scala IDE

对于那些喜欢功能性语言的开发者来说,Scala 一直以来都充满吸引力,它提供功能性语言的生产结构和支持,同时可以与来自 Java 世界的庞大代码库一起工作。Scala 在 JVM 上运行,它可以链接任何 JAR 文件。因此,Scala 爱好者为 Eclipse 创建一个 Scala IDE(http://scala-ide.org/) 也就不足为奇了,他们可以利用 Eclipse 的强大功能来构建他们喜欢的应用程序。

Kotlin

很多人把 Kotlin 看成 Java 的简化版。Kotlin 拥有丰富的函数式编程特性,擅长处理空值,具有与 Java 的互操作性,能够生成 JavaScript 和 native 代码,它受到 Android 开发者的强烈追捧。如果你想加入 Kotlin 的潮流, 那么针对 Eclipse 的 Kotlin(https://marketplace.eclipse.org/content/kotlin-plugin-eclipse) 插件将是你的不二选择。

YEdit

如今并不是所有人都热衷于使用 JSON 格式来存储数据。现今另一个热门的方式是 YAML。树结构一样,数据也几乎相同,它使用缩进而不是大括号。YEdit(https://marketplace.eclipse.org/content/yedit) 是一个简易创建 YAML 文件的工具。它的基本概念不难理解,但有时候对于缩进的使用需要一点帮助。

UML Designer

我至始至终都不明白 UML(统一建模语言)有何吸引力,但是仍然有相当数量的人喜欢它,喜欢使用来自 Obeo 的 Eclipse 插件 UML Designer(https://marketplace.eclipse.org/content/uml-designer)。UML 是用于指定、创建和记录面向对象编程项目元素的标准。当你画出长方形,所有人都能明白你的意图。该插件还让你可以深入定义 UML 的 XML 树形表示。如果你喜欢 UML ,那么你可能也会喜欢UML Lab Class Diagram Editor(https://marketplace.eclipse.org/content/uml-lab-class-diagram-editor/metrics) 和 UML Java Generator(https://marketplace.eclipse.org/content/uml-java-generator/metrics)。

ImageJ

Eclipse 通常情况的使用者是程序员,但是随着计算机渗透到更多科学领域,越来越多科学家+程序员双重身份的人开始涌现。的确,你很难找到一个完全不会写代码的科学家。ImageJ(https://marketplace.eclipse.org/content/imagej-plugin) 是一个强大的图像分析程序,它彻底改变了大量视觉数据的收集方式。如果你在 Eclipse 中运行它,可以编写自定义的代码来自动完成下一篇论文所需的所有数据的收集和整理。

作者:csdnnews 发表于2017/11/10 8:48:28 原文链接
阅读:3879 评论:3 查看评论

爬虫入门-02-爬虫模块介绍

$
0
0

爬虫入门-爬虫模块介绍

Python的urllib和urllib2模块都做与请求URL相关的操作,但他们提供不同的功能。
他们两个最显着的差异如下:

  • urllib2可以接受一个Request对象,并以此可以来设置一个URL的headers,但是urllib只接收一个URL。
    这意味着,你不可以通过urllib模块伪装你的User Agent字符串等(伪装浏览器)。
  • urllib2模块比较优势的地方是urlliburllib2.urlopen可以接受Request对象作为参数,从而可以控制HTTP Request的header部。

  • urllib模块可以提供进行urlencode的方法,该方法用于GET查询字符串的生成,urllib2的不具有这样的功能。

  • urllib.urlretrieve函数以及urllib.quote等一系列quote和unquote功能没有被加入urllib2中,因此有时也需要urllib的辅助。

这就是urllib与urllib2经常在一起使用的原因。

Google调试:F12
爬虫常用:
1) Sources (js源码)
2) Elements(页面元素)
3) Network(网络请求)

  • user-agent 电脑打开微信网页显示无法打开,就是修改了user-agent参数
  • referer参数地址,是上一个页面的地址链接,简单反扒处理
  • cookie 服务器返回的cookie,保存一些参数,下一次请求会覆盖旧的cookie

常用的方法

1) urllib2.urlopen(url[, data][, timeout])

  urlopen方法是urllib2模块最常用也最简单的方法,它打开URL网址,url参数可以是一个字符串url或者是一个Request对象。URL没什么可说的,Request对象和data在request类中说明,定义都是一样的。

  对于可选的参数timeout,阻塞操作以秒为单位

import urllib2
response = urllib2.urlopen('http://python.org/')
html = response.read()

urlopen方法也可通过建立了一个Request对象来明确指明想要获取的url。调用urlopen函数对请求的url返回一个response对象。这个response类似于一个file对象,所以用.read()函数可以操作这个response对象,关于urlopen函数的返回值的使用,我们下面再详细说。

import urllib2
req = urllib2.Request('http://python.org/')
response = urllib2.urlopen(req,data='abc')
the_page = response.read()

2) urllib2.Request(url[, data][, headers][, origin_req_host][, unverifiable])

Request类是一个抽象的URL请求。
这里用到了urllib2.Request类,对于上例,我们只通过了URL实例化了Request类的对象,其实Request类还有其他的参数。
data是作为参数请求,如果data不等于None,则该请求为POST,否则为GET

import urllib
import urllib2
url = 'http://www.baidu.com'
values = {'name' : 'test',
          'age' : 27,
          'id' :1}
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
the_page = response.read()

headers——是字典类型,头字典可以作为参数在request时直接传入,也可以把每个键和值作为参数调用add_header()方法来添加。作为辨别浏览器身份的User-Agent header是经常被用来恶搞和伪装的,因为一些HTTP服务只允许某些请求来自常见的浏览器而不是脚本,或是针对不同的浏览器返回不同的版本。例如,Mozilla Firefox浏览器被识别为“Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11”。默认情况下,urlib2把自己识别为Python-urllib/x.y(这里的xy是python发行版的主要或次要的版本号,如在Python 2.6中,urllib2的默认用户代理字符串是“Python-urllib/2.6。下面的例子和上面的区别就是在请求时加了一个headers,模仿IE浏览器提交请求。

import urllib
import urllib2
url = 'http://www.baidu.com'
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
values = {'name' : 'test',
          'age' : 27,
          'id' :1}
headers = { 'User-Agent' : user_agent }
data = urllib.urlencode(values)
req = urllib2.Request(url, data, headers)
response = urllib2.urlopen(req)
the_page = response.read()

添加header也可以采用另一种方案

req.add_header('Referer', 'http://www.python.org/')

3)其他的一些常用方法
geturl() — 返回检索的URL资源,这个是返回的真正url,通常是用来鉴定是否重定向的,如下面代码4行url如果等于“http://www.python.org/ ”说明没有被重定向。如果被重定向了,有可能这个被重定向的值是需要用的,比如下载的时候如果我们要获取那个最终的下载地址
getcode() — 返回响应的HTTP状态代码,运行下面代码可以得到code=200,具体各个code代表的意思请参见文后附录。

4)HTTPCookieProcessor
很多网站的资源需要用户登录之后才能获取。
我们一旦登录后再访问其他被保护的资源的时候,就不再需要再次输入账号、密码。那么网站是怎么办到的呢?
一般来说,用户在登录之后,服务器端会为该用户创建一个Session。Session相当于该用户的档案。该档案就代表着该用户。
那么某一次访问请求是属于该用户呢?登录的时候服务器要求浏览器储存了一个Session ID的Cookie值。每一个访问都带上了该Cookie。服务器将Cookie中的Session ID与服务器中的Session ID比对就知道该请求来自哪个用户了。

opener
我们在调用urllib2.urlopen(url)的时候,其实urllib2在open函数内部创建了一个默认的opener对象。然后调用opener.open()函数。
但是默认的opener并不支持cookie。
那么我们先新建一个支持cookie的opener。urllib2中供我们使用的是HTTPCookieProcessor。

创建HTTPCookieProcessor需要一个存放cookie的容器。
Python提供的存放cookie的容器位于cookielib,有以下几个。
CookieJar -> FileCookieJar -> MozillaCookieJar / LWPCookieJar

import cookielib
import urllib2

cookies = cookielib.CookieJar()
cookieHandler = urllib2.HTTPCookieProcessor(cookiejar=cookies)
opener = urllib2.build_opener(cookieHandler)

request = urllib2.Request("http://www.baidu.com")
urllib2.urlopen(request)
for cookie in cookies:
    print cookie.name, cookie.value

上面的代码显示,urllib2的确帮我们把cookie从response中提取出来。但是如何保存在一个文件中呢?

urllib2.install_opener(opener)

会设置 urllib2 的全局 opener

最后来讲解下这个json包
json.dumps 将 Python 对象编码成 JSON 字符串
json.loads 将已编码的 JSON 字符串解码为 Python 对象

作者:lianjiaokeji 发表于2017/11/10 9:49:03 原文链接
阅读:91 评论:0 查看评论

使用FFmpeg实现抠图合并功能(chroma key)

$
0
0

自己以前实现抠图算法好久了,没想到ffmpeg里面早有这个功能了

在很多视频中可以看到图像是合成的,例如有些神剧里面某大侠跳下万丈深渊的场景,某人在三昧真火中被烧的场景,还有些游戏主播,体育主播在主场景前面有个人解说的场景,都是chroma key的技术实现的,具体的链接可以参考:

效果图如下:

在最新版本的ffmpeg中,已经增加了chroma key功能的filter,只需要一条命令即可搞定

点击(此处)折叠或打开

  1. ./ffmpeg -i ~/fuck.mp4 -i ~/1.mp4 -shortest -filter_complex "[1:v]chromakey=0x70de77:0.1:0.2[ckout];[0:v][ckout]overlay[out]" -map "[out]" output.mp4


将1.mp4中的人物抠出来,合并到fuck.mp4中,就可以搞定了
合并之前的1.mp4的效果

执行命令行如下:

与fuck合并后的效果
作者:feixiang_john 发表于2017/11/10 14:23:20 原文链接
阅读:92 评论:0 查看评论

对一文进行补充

$
0
0

MS 曾在他的Github站点上提出过《源码级调试WDF框架》的方法,文中提到通过.srcfix命令使windbg源码服务器路径指向MS的源码服务器。这样当调试到wdf框架代码时,windbg会去源码服务器下载对应的源码并加载显示在源码窗口。

我尝试过这种方法,然而结果并不像预计的那样:

0: kd> .reload /f wdf01000.sys
0: kd> !lmi wdf01000.sys
Loaded Module Info: [wdf01000.sys] 
...
       Compiler: C - front end [19.10 bld 25203] - back end [19.10 bld 25203]
    Load Report: private symbols & lines, source indexed 
                 C:\Users\q50292th\Desktop\devtools\windbg v10\x64\sym\Wdf01000.pdb\98BFF4E535208A77013A260DE4A248201\Wdf01000.pdb
0: kd> lsa Wdf01000!FxDevice::DispatchWithLock
No source found for 'minkernel\wdf\framework\shared\core\fxdevice.cpp'
在显示源码过程中,windbg会启动一个功能类似svn客户端的程序,尝试去下载源文件并保存到windbg目录的src目录下。但是不知道是不是GWF的原因,源文件一直无法获得和显示。导致了上面lsa命令运行失败。

那么,是不是就不支持源码级调试WDF框架?倒也不是。办法还是有的。MS还是好心把Wdf框架的源码全部放在GitHub上,可以把源码下到本地,然后运行如下命令:

.srcfix C:\srcfix\Windows-Driver-Frameworks-master\src\framework  ;我将GitHub上的代码解压保存到C:\srcfix\Windows-Driver-Frame-master下

这是我机器上.srcpath显示的结果:

kd> .srcpath
Source search path is: SRV*;C:\srcfix\Windows-Driver-Frameworks-master\src\framework;
另外还需要安装Driver kit,因为调试过程中windbg会尝试去C:\Program Files (x86)\Windows Kits\目录下搜索头文件。如果搜索不到,还是不支持源码级调试。

经过以上设置,基本能实现源码级调试WDF框架~以MS toast(wdfsimple.sys)为例,进入WdfSimple!DriverEntry并调用WdfDriverCreate函数后的调用堆栈:

kd> kb
RetAddr           : Args to Child                                                           : Call Site
fffff803`aed21206 : 00000000`00000000 fffff803`aed211c4 00000000`00000010 00000000`00000344 : 
			Wdf01000!imp_WdfDriverCreate+0x44 [minkernel\wdf\framework\shared\core\fxdriverapi.cpp @ 105]

fffff803`aed26053 : ffff920f`b8929a00 ffff920f`b94be000 00000000`00000000 ffff8384`57c7d2d8 : 
			wdfsimple!WdfDriverCreate+0x56 [c:\program files (x86)\windows kits\10\include\wdf\kmdf\1.15\wdfdriver.h @ 239]

fffff803`aed21499 : ffff920f`b8929a00 ffff920f`b94be000 ffffb889`e5b548d0 ffff920f`b89d87c0 : 
			wdfsimple!DriverEntry+0x53 [f:\twl\general\toaster\toastdrv\kmdf\func\simple\toaster.c @ 93]

fffff801`856e257a : 00000000`00000000 ffff8384`57c7d440 ffff920f`b8929a00 ffffffff`80002328 : 
			wdfsimple!FxDriverEntryWorker+0xb9 [d:\th\minkernel\wdf\framework\kmdf\src\dynamic\stub\stub.cpp @ 325]
以及对应的Wdf函数源码:

kd> .frame 1
01 ffff8384`57c7d260 fffff803`aed26053 
	wdfsimple!WdfDriverCreate+0x56 [c:\program files (x86)\windows kits\10\include\wdf\kmdf\1.15\wdfdriver.h @ 239]
kd> lsa fffff803`aed26053 
    89: 
    90:     //
    91:     // Create a framework driver object to represent our driver.
    92:     //
>   93:     status = WdfDriverCreate(
    94:         DriverObject,
    95:         RegistryPath,
    96:         WDF_NO_OBJECT_ATTRIBUTES, // Driver Attributes
    97:         &config,          // Driver Config Info
    98:         WDF_NO_HANDLE
kd> .frame 0
00 ffff8384`57c7d0d0 fffff803`aed21206 
	Wdf01000!imp_WdfDriverCreate+0x44 [minkernel\wdf\framework\shared\core\fxdriverapi.cpp @ 105]
kd> lsa fffff803`aed21206
   235:     WDFDRIVER* Driver
   236:     )
   237: {
   238:     return ((PFN_WDFDRIVERCREATE) WdfFunctions[WdfDriverCreateTableIndex])(WdfDriverGlobals, DriverObject, RegistryPath, DriverAttributes, DriverConfig, Driver);
>  239: }
   240: 
   241: //
   242: // WDF Function: WdfDriverGetRegistryPath
   243: //
   244: typedef

目标实现~

参考:Debugging with WDF Source







作者:lixiangminghate 发表于2017/11/10 14:37:35 原文链接
阅读:50 评论:0 查看评论

Ubuntu server 1404 SSH 远程搭建

$
0
0


因为我装的是 ubuntu server 1404 版本 没有图形界面的 搭建服务器用的

所以 用ssh     

命令行内 直接

$ sudo apt-get install openssh-server

重启  $ssh start


【注意】

因为在安装的时候没有联网(服务器的网不好弄)  所以装完后 什么都没有连 源也没有;  先 换源,  换源后 开始装 软件,

可能这个原因,  我装的过程中没有出现 太多的问题


装完后,  windows 电脑 就可以下载 PuTTY_(远程)  和 FileZilla (传文件用的)  

文件都不大

打开 直接输入  服务器ip地址 默认端口22  进去后 输入用户名和密码就可以了

FileZilla 也是一样道理

作者:sizaif 发表于2017/11/10 15:42:10 原文链接
阅读:0 评论:0 查看评论

LWC 57:721. Accounts Merge

$
0
0

LWC 57:721. Accounts Merge

传送门:721. Accounts Merge

Problem:

Given a list accounts, each element accounts[i] is a list of strings, where the first element accounts[i][0] is a name, and the rest of the elements are emails representing emails of the account.

Now, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some email that is common to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name.

After merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails in sorted order. The accounts themselves can be returned in any order.

Example 1:

Input:
accounts = [[“John”, “johnsmith@mail.com”, “john00@mail.com”], [“John”, “johnnybravo@mail.com”], [“John”, “johnsmith@mail.com”, “john_newyork@mail.com”], [“Mary”, “mary@mail.com”]]
Output: [[“John”, ‘john00@mail.com’, ‘john_newyork@mail.com’, ‘johnsmith@mail.com’], [“John”, “johnnybravo@mail.com”], [“Mary”, “mary@mail.com”]]
Explanation:
The first and third John’s are the same person as they have the common email “johnsmith@mail.com”.
The second John and Mary are different people as none of their email addresses are used by other accounts.
We could return these lists in any order, for example the answer [[‘Mary’, ‘mary@mail.com’], [‘John’, ‘johnnybravo@mail.com’],
[‘John’, ‘john00@mail.com’, ‘john_newyork@mail.com’, ‘johnsmith@mail.com’]] would still be accepted.

Note:

  • The length of accounts will be in the range [1, 1000].
  • The length of accounts[i] will be in the range [1, 10].
  • The length of accounts[i][j] will be in the range [1, 30].

思路:
很暴力,简单的从头到尾慢慢添加新来的信息。首先,如果该用户在原先的数据库中不存在,则可以直接加入数据库。如果该用户存在与数据库,注意两种情况:

  • 同名, 但没有邮箱重复,说明不是同一个人,直接加入数据库。
  • 同名,且邮箱有重复,说明是同一个人,则把所有关联的邮箱进行合并即可。

代码如下:

    public List<List<String>> accountsMerge(List<List<String>> accounts) {
        Map<String, List<Set<String>>> mem = new HashMap<>();
        int n = accounts.size();
        for (int i = 0; i < n; ++i) {
            List<String> account = accounts.get(i);
            String name = account.get(0);
            if (mem.containsKey(name)) {
                List<Set<String>> mm = mem.get(name);
                int idx = -1;
                Set<String> hh = new HashSet<>();
                for (int k = 1; k < account.size(); ++k){
                    hh.add(account.get(k));
                }
                Set<Integer> mer = new HashSet<>();
                for (int k = 1; k < account.size(); ++k) {
                    String email = account.get(k);
                    for (int j = 0; j < mm.size(); ++j) {
                        if (mm.get(j).contains(email)) {
                            idx = j;
                            mer.add(idx);
                        }
                    }
                }

                if (mer.size() == 0) { // 同名,属于两个人
                    mem.computeIfAbsent(name, k -> new ArrayList<>()).add(hh);
                }
                else { // 属于同一个人
                    // 邮箱合并
                    List<Integer> merge = new ArrayList<>();
                    merge.addAll(mer);

                    mm.get(merge.get(0)).addAll(hh);
                    List<Set<String>> removes = new ArrayList<>();
                    for (int j = 1; j < merge.size(); ++j) {
                        mm.get(merge.get(0)).addAll(mm.get(merge.get(j)));
                        removes.add(mm.get(merge.get(j)));
                    }

                    // 删除之前的邮箱
                    for (Set<String> re : removes) {
                        mm.remove(re);
                    }
                }
            }
            else {
                // 数据库中不存在该用户,直接加入数据库
                Set<String> mails = new HashSet<>();
                for (int j = 1; j < account.size(); ++j) {
                    mails.add(account.get(j));
                }
                mem.computeIfAbsent(name, k -> new ArrayList<>()).add(mails);
            }
        }

        List<List<String>> ans = new ArrayList<>();
        for (String key : mem.keySet()) {
            List<Set<String>> val = mem.get(key);
            for (int i = 0; i < val.size(); ++i) {
                List<String> vv = new ArrayList<>();
                vv.addAll(val.get(i));
                Collections.sort(vv);
                List<String> tmp = new ArrayList<>();
                tmp.add(key);
                tmp.addAll(vv);
                ans.add(tmp);
            }
        }
        return ans;
    }
作者:u014688145 发表于2017/11/10 15:58:36 原文链接
阅读:31 评论:0 查看评论

第7章 套接字选项

$
0
0

套接字选项相关函数:

#include <sys/socket.h>

int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);



#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );


作者:gongluck93 发表于2017/11/10 10:54:54 原文链接
阅读:33 评论:0 查看评论

0基础lua学习(十七)C调用Lua----01小demo

$
0
0

一、Lua介绍

Lua 是一个嵌入式的语言,Lua 解释器是一个使用 Lua 标准库实现的独立的解释器,她是一个很小的应用(总共不超过 500 行的代码)。解释器负责程序和使用者的接口:从使用者那里获取文件或者字符串,并传给 Lua 标准库, Lua 标准库负责最终的代码运行。

1.Lua 作为扩展性语言和可扩展的语言

Lua 可以作为程序库用来扩展应用的功能,Lua 程序中可以注册有其他语言实现的函数,这些函数可能由 C 语言(或其

他语言)实现,可以增加一些不容易由 Lua 实现的功能。

2.C 和 Lua 中间有两种交互方式

  •  C 作为应用程序语言, Lua 作为一个库使用;
  •  反过来, Lua 作为程序语言, C 作为库使用。


这两种方式, C 语言都使用相同的 API 与 Lua 通信,因此 C 和Lua 交互这部分称为 C API。

(C API 是一个 C代码与 Lua 进行交互的函数集。他有以下部分组成:读写Lua 全局变量的函数,调用 Lua 函数的函数,运行Lua 代码片断的函数,注册 C 函数然后可以在
Lua 中被调用的函数,等等。)

------------C API介绍-------------------------------------------------
C API 遵循C 语言的语法形式,这 Lua 有所不同。当使用 C进行程序设计的时候,我们必须注意,类型检查,错误处理,内存分配都很多问题。

API 中的大部分函数并不检查他们参数的正确性;你需要在调用函数之前负责确保参数是有效的。如果你传递了错误的参数,可能得到 \"segmentation fault\" 这样或者类似的错误信息,而没有很明确的错误信息可以获得。

另外, API重点放在了灵活性和简洁性方面,有时候以牺牲方便实用为代价的。一般的任务可能需要涉及很多个 API 调用,这可能令人烦恼,但是他给你提供了对细节的全部控制的能力,比如错误处理,缓冲大小,和类似的问题。

-------------------------------------------------------------

3.在 C 和 Lua 之间通信关键内容在于一个虚拟的栈。

几乎所有的API 调用都是对栈上的值进行操作,所有 C 与 Lua 之间的数据交换也都通过这个栈来完
成。另外,你也可以使用栈来保存临时变量。栈的使用解决了 C 和 Lua 之间两个不协调Programming in Lua
的问题:

第一, Lua 会自动进行垃圾收集,而 C 要求显示的分配存储单元,两者引起的矛盾。

第二, Lua 中的动态类型和 C 中的静态类型不一致引起的混乱。


~~以上摘自《Programming in Lua》


二、配置环境


             1、首先下载lua for windows,我使用的是 Lua 5.1

             2、在vs2015/vs2012/vs2010/VS2005上配置lua环境

I、添加lua头文件包含目录
项目->属性->配置属性->C/C++->常规->附加包含目录:C:\Program Files (x86)\Lua\5.1\include(根据你的lua安装路径设置)

II、添加静态库目录
项目->属性->配置属性->连接器->常规->附加库目录:C:\Program Files (x86)\Lua\5.1\lib(根据你的lua安装路径设置)

III、添加引用库
项目->属性->配置属性->连接器->输入->附加依赖库:lua51.lib


二、编写hello,world


1、新建一个空的win32工程(lua_test),添加一个源文件lua_test.cpp

2、用文本编辑器创建一个lua脚本(hello.lua),内容如下:

下面代码如果编译通过,说明调用成功


// prj.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <intrin.h>

int _tmain(int argc, _TCHAR* argv[])
{    

        char buff[256];
        int error;
        lua_State *L = lua_open(); /* opens Lua */
        luaopen_base(L); /* opens the basic library */
        luaopen_table(L); /* opens the table library */
        luaopen_io(L); /* opens the I/O library */
        luaopen_string(L); /* opens the string lib. */
        luaopen_math(L); /* opens the math lib. */
        while (fgets(buff, sizeof(buff), stdin) != NULL) {
            error = luaL_loadbuffer(L, buff, strlen(buff),
                "line") || lua_pcall(L, 0, 0, 0);
            if (error) {
                fprintf(stderr, "%s", lua_tostring(L, -1));
                lua_pop(L, 1);/* pop error message from the stack */
            }
        }
        lua_close(L);
        return 0;

}


lua.h 定义了 Lua 提供的基础函数。其中包括创建一个新的Lua 环境的函数
(如
lua_open),调用 Lua 函数(如 lua_pcall)的函数,读取/写入Lua 环境的全局变量
的函数,注册可以被 Lua代码调用的新函数的函数,等等。所有在 lua.h中被定义的都
有一个
lua_前缀。

lauxlib.h:定义了辅助库( auxlib)提供的函数。同样,所有在其中定义的函
数等都以
luaL_打头(例如, luaL_loadbuffer)。


ps:
Lua 库没有定义任何全局变量。它所有的状态保存在动态结构lua_State 中,而且指
向这个结构的指针作为所有
Lua 函数的一个参数。这样的实现方式使得Lua 能够重入
reentrant)且为在多线程中的使用作好准备。


  • 函数 lua_open 创建一个新环境(或state)。 lua_open创建一个新的环境时,这个环境并不包括预定义的函数,甚至是 print
  • 为了保持 Lua 的苗条,所有的标准库以单独的包提供,所以如果你不需要就不会强求你使用它们。头文件 lualib.h 定义了打开这些库的函数。例如,调用 luaopen_io,以创建io table 并注册 I/O 函数( io.read,io.write等等)到 Lua 环境中。
  • 创建一个 state 并将标准库载入之后,就可以着手解释用户的输入了。对于用户输入的每一行, C 程序首先调用 luaL_loadbuffer 编译这些 Lua 代码。如果没有错误,这个调用返回零并把编译之后的 chunk压入栈之后, C程序调用 lua_pcall,它将会把 chunk 从栈中弹出并在保护模式下运行它。和luaL_laodbuffer 一样,lua_pcall 在没有错误的情况下返回零。
  • 在有错误的情况下,这两个函数都将一条错误消息压入栈;我们可以用 lua_tostring来得到这条信息、输出它,用lua_pop 将它从栈中删除。

三、你可以将 LuaC/C++

代码一起编译, lua.h 并不包含这些典型的在其他 C 库中出现的整合代码:

#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif

因此,如果你用 C方式来编译它,但用在 C++中,那么你需要象下面这样来包含lua.h
头文件。
extern "C" {
#include <lua.h>
}
一个常用的技巧是建立一个包含上面代码的 lua.hpp头文件,并将这个新的头文件包
含进你的
C++程序。


以上大部分是《Programming in Lua 》的缩略版,

概书在第24章 C API纵览,详细的介绍了这方面内容,过于细致,所以我精简了一部分,外加自己的一些补充。


作者:hiwoshixiaoyu 发表于2017/11/10 11:23:07 原文链接
阅读:26 评论:0 查看评论
Viewing all 35570 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>