网赚多少全看努力与否

mikel阅读(882)

很多时候, 人就是懒,就是明明白白告诉他这样执行下去能赚钱,重要是坚持,可他就是坚持不下去,那么再好的项目也不会被他做好。

反观那些努力执行力强的,就会发现一个共同点韧劲十足,从我的体验站每天的提现情况就可以看出,那些多次提现的,不是那些猛人,反而是那些做推广的和每天签到的,记忆犹新的是一个哥们儿坚持签到了2年申请的提现。可能你对此嗤之以鼻,觉得这种人没什么长进,也成功不了,但是人家就是务实,踏踏实实的签到,钱很少才几分钱,但是人家就是坚持做了,你有什么资格取消别人,你也签两年到试试?!

从此可以看出成功者还是少数,不管是网赚行业,还是程序开发行业,成功的人很少,究其原因就是人的问题,人没有韧性,不脚踏实地成功不了,那些只知道圈钱、风投、玩儿概念的都是出了名的大忽悠,赚到钱了吗?不得而知,反正我是不信。

所以说别总觉得网上赚钱难,很多时候我们都把困难放大化了给自己找借口,你说建网站难,可是很多50多的老大爷都能建个自己的网站推广赚钱,你又怎么说?!不要找借口,别想那么多,别看不起蝇头小利,做了再说!努力与否别人的眼睛是雪亮的。

一篇文档的故事

mikel阅读(931)

很多人都知道豆丁网,就是那个可以上传文档定价销售赚钱的网站,别人下载支付豆币给你,你豆币到一定额度可以提现的网站

可怜的1豆币还不到1分钱,很多人嗤之以鼻,觉得赚不到钱,于是没人做,大多是搞营销的发软文到里面,加上链接来营销自己的项目用,毕竟搜索引擎收录豆丁的权重还是蛮高的。

看似不赚钱的项目,居然有人月赚2000,这是靠什么赚这么多,靠的就是人家的坚持,每天上传文档,蚂蚁小也是肉,人家以量取胜,一样能赚到钱,尽管前期一年不怎么赚钱,但是一旦坚持一年下来,就可以赚这么多。

生存大于梦想

mikel阅读(1616)

真得梦想只是个无法充饥的梦而已,那是能够吃饱饭,不再发愁生存的成功者后来书写自己成功史的词令。

创业初期没有生存机会,就是死亡。死亡就是这么被梦想的光环遮掩在光明的前途里面,于是很多人迷恋上了扩张而忘记了自己的生存还难以为继,于是创业的世界变得光明无比。

如何创业没有定律!但是创业伙伴很难找到哪种程度,首先要维持伙伴的家庭的生计,毕竟大家不可能抛家撇口的来跟你一起创业,没有饭吃谁还想着什么创业、梦想?!

所以说要想创业不要找人合伙,自己当老板即可,不会有什么心理上的歉疚和不安,觉得对不起合伙人。只需要招员工,给工资,做自己的业务赚钱,赚不到钱自己想办法就行了,世界就是这样的现实,与你同甘共苦的人很少,生存大于梦想!

两条腿走路 走得稳

mikel阅读(1010)

任何时候不要让自己的命运维系在一项事业上,否则会急功近利的想做好,但是越是这样越做不好,为什么,因为你没有任何后路可走。

可能这也让很多人觉得有点儿偷奸耍滑的嫌疑,做什么事儿都不能全力以赴,但是做事要全力以赴,不代表不给自己留后路,谁知道未来会是什么样?

 

一个"创"字 道尽创业的艰辛

mikel阅读(940)

创业的人都希望能够做出一番事业,所以才会叫”创”!一个”创”字道尽多少艰辛,谁能了得?!

资金、市场、人三方面不可缺少,可有多少创业者三者兼具,都是在辛苦的打拼中做出来的。

我目前的状态就是起步创业,就举步维艰,要养家糊口,不能没有收入。和别人合作创业,同样是不稳定的业务和市场,收入总是保证不了,于是面临的就是家庭的压力和生存的需要。

创业的同时就要做好自己失败的准备,毕竟岁月不饶人,尽管是创业的好时候,可为人父为人子为人夫的责任不允许自己孤注一掷的创,所以说对于我来说业要创,家也要管,否则都会搞砸了。

没有勇气创不了业,没有能力同样如此,什么是能力?不仅仅是技术,还要有人际关系等等方面,所以说找创业伙伴就是个相当重要的问题,合伙了,就会有利益之分,多少都不合适。

创业最煎熬的是入不敷出,没有稳定的项目和资金流支撑公司的正常运转,很难创好业。

[转载]【C#】教你纯手工用C#实现SSH协议作为GIT服务端 - Aimeast - 博客园

mikel阅读(890)

来源: [转载]【C#】教你纯手工用C#实现SSH协议作为GIT服务端 – Aimeast – 博客园

SSH(Secure Shell)是一种工作在应用层和传输层上的安全协议,能在非安全通道上建立安全通道。提供身份认证、密钥更新、数据校验、通道复用等功能,同时具有良好的可扩展性。本文从SSH的架构开始,教你纯手工打造SSH服务端,顺便再教你如何利用SSH服务端实现Git服务端协议。

目录

  1. SSH架构
  2. 建立传输层
    1. 交换版本信息
    2. 报文结构
    3. 算法
    4. 算法选择
    5. 密钥交换
    6. 密钥更新
    7. 使用算法
    8. 数据包封装
  3. 身份认证
  4. 使用连接层服务
  5. 实现Git服务端协议
  6. 打个广告

一、SSH架构

SSH 1.x协议已经过时,当前版本为2.0。主要由如下RFC文档描述:

另外还有若干RFC在上述基础上对协议进行扩展,本文主要对上述RFC内容进行介绍。建议上述文档按照从上至下的顺序阅读。最为麻烦的是SSH传输 层协议,需要实现算法协商、交换密钥、数据加密、数据压缩、数据校验的算法。这部分的实现需要一定的算法功底,不过还好Fx帮我们实现了许多密码学算法, 但是坑爹的是Fx并没有实现SSH所推荐的CTR工作模式。 其中认证协议和连接协议作为SSH内置服务。认证协议提供了基于密码和基于密钥的身份认证方式。客户端不会无端的请求进行身份认证,每次身份认证都是为了 请求某一服务的授权。但是前面也说了,当前SSH内置的两个服务分别是身份认证和连接协议,身份认证所请求授权的服务一定是链接协议。当然了,不能排除其 他RFC会扩展出新的服务。

二、建立传输层

1. 交换版本信息

服务端默认监听22端口,建立TCP连接后客户端和服务端分别发送版本交换信息,格式为:SSH-protoversion-softwareversion SP comments CR LF。其中协议版本必须为2.0,无论Windows还是Linux或是Mac,必须以CRLF结尾,包括换行符总长度不超过255字节。服务端在发送版本交换信息之前,可能会发送若干行不以SSH-打头的欢迎信息,同样以CRLF作为换行符。版本交换信息不允许包含null。版本交换信息的bytes作为Diffie-Hellman密钥交换的输入之一。RFC考虑了2.0协议如何兼容1.x协议,本文不做介绍。

2. 报文结构

SSH报文封装见下图,点击图片可以放大(图片来自wiki,如果看不到请自备梯子)。

协议实现过程中发现比较大的一个坑是RFC4251中定义的mpint数据类型,其表示长度可变的整数。当时没有严格的阅读定义就开始敲代码,结果导致有50%的概率密钥交换失败。就是因为没能正确的区分正负数的表示形式。

3. 算法

SSH主要由下列类型的算法作为基础:

必须支持的算法原则上需要实现。当然了,如果你肯定的知道对方支持哪些算法,可以偷懒不实现某些必须支持的算法。算法的具体实现请参考RFC文档中相关引用。

4. 算法选择

双方交换完版本信息后,接着发送所支持算法。报文格式为:先发送SSH_MSG_KEXINIT作为报文标识,紧接着是16字节的随机数,接下来是10个name-list(定义见RFC4251)表示支持的算法,最后是first_kex_packet_follows和一个uint32的0。对于first_kex_packet_follows,我表示这是蛋疼的参数,果断没有进行支持。具体格式如下:

byte         SSH_MSG_KEXINIT
byte[16]     cookie (random bytes)
name-list    kex_algorithms
name-list    server_host_key_algorithms
name-list    encryption_algorithms_client_to_server
name-list    encryption_algorithms_server_to_client
name-list    mac_algorithms_client_to_server
name-list    mac_algorithms_server_to_client
name-list    compression_algorithms_client_to_server
name-list    compression_algorithms_server_to_client
name-list    languages_client_to_server
name-list    languages_server_to_client
boolean      first_kex_packet_follows
uint32       0 (reserved for future extension)

客户端和服务端的选择算法是一致的(废话,要不然双方怎么选择)。用一个字表示是:优先选择客户端靠前的算法。实现算法如下:

private string ChooseAlgorithm(string[] serverAlgorithms, string[] clientAlgorithms)
{
    foreach (var client in clientAlgorithms)
        foreach (var server in serverAlgorithms)
            if (client == server)
                return client;
}
5. 密钥交换

算法选择后,客户端发送SSH_MSG_KEXDH_INIT数据包,发送Diffie-Hellman参数e。服务端响应SSH_MSG_KEXDH_REPLY回复参数K_Sfhash(H)。客户端验证回复参数后响应SSH_MSG_NEWKEYS,之后服务端也响应SSH_MSG_NEWKEYS,之后客户端与服务端使用新的密钥进行加密和校验数据。

按照Diffie-Hellman算法,客户端和服务端分别使用参数ef计算出Shared Secret,然后计算出Exchange Hash,再进一步计算出客户端和服务端加密密钥、初始向量、消息签名密钥。第一次计算出的Exchange Hash作为当次会话的Session Id,作为会话的永久识别标识。

其中K_S是服务端公钥,rsa和dss的序列化格式稍有差异。第一个字段是算法当前算法名称,接下来若干个mpint表示当前算法的公钥参数。

H是当前能获取到的所有参数(包括噪音)的集合,包括了客户端和服务端版本标识、客户端和服务端SSH_MSG_KEXINIT消息的载荷、服务端公钥、efShared Secret。数据格式如下:

string    V_C, the client's identification string (CR and LF excluded)
string    V_S, the server's identification string (CR and LF excluded)
string    I_C, the payload of the client's SSH_MSG_KEXINIT
string    I_S, the payload of the server's SSH_MSG_KEXINIT
string    K_S, the host key
mpint     e, exchange value sent by the client
mpint     f, exchange value sent by the server
mpint     K, the shared secret

接下来是计算各种密钥,这部分用文字、用数学符号都不便表述,分还是用代码表述比较清晰。直接上代码:

var clientCipherIV = ComputeEncryptionKey(kexAlg, exchangeHash, clientCipher.BlockSize >> 3, sharedSecret, 'A');
var serverCipherIV = ComputeEncryptionKey(kexAlg, exchangeHash, serverCipher.BlockSize >> 3, sharedSecret, 'B');
var clientCipherKey = ComputeEncryptionKey(kexAlg, exchangeHash, clientCipher.KeySize >> 3, sharedSecret, 'C');
var serverCipherKey = ComputeEncryptionKey(kexAlg, exchangeHash, serverCipher.KeySize >> 3, sharedSecret, 'D');
var clientHmacKey = ComputeEncryptionKey(kexAlg, exchangeHash, clientHmac.KeySize >> 3, sharedSecret, 'E');
var serverHmacKey = ComputeEncryptionKey(kexAlg, exchangeHash, serverHmac.KeySize >> 3, sharedSecret, 'F');

其中

private byte[] ComputeEncryptionKey(KexAlgorithm kexAlg, byte[] exchangeHash, int blockSize, byte[] sharedSecret, char letter)
{
    var keyBuffer = new byte[blockSize];
    var keyBufferIndex = 0;
    var currentHashLength = 0;
    byte[] currentHash = null;

    while (keyBufferIndex < blockSize)
    {
        using (var worker = new SshDataWorker())
        {
            worker.WriteMpint(sharedSecret);
            worker.Write(exchangeHash);

            if (currentHash == null)
            {
                worker.Write((byte)letter);
                worker.Write(SessionId);
            }
            else
            {
                worker.Write(currentHash);
            }

            currentHash = kexAlg.ComputeHash(worker.ToByteArray());
        }

        currentHashLength = Math.Min(currentHash.Length, blockSize - keyBufferIndex);
        Array.Copy(currentHash, 0, keyBuffer, keyBufferIndex, currentHashLength);

        keyBufferIndex += currentHashLength;
    }

    return keyBuffer;
}

如果实在想看看文字描述求虐的,移步到RFC的Diffie-Hellman Key Exchange小结。

6. 密钥更新

SSH允许每个一段时间或传输一定量数据后,由任意一方再次发起密钥交换。再次密钥交换的过程与上述过程一致。无论是客户端还是服务端发起再次交换密钥的请求,原客户端和服务端的角色不改变。密钥更新过程中除了密钥交换的数据包,别的数据包都禁止发送。再次密钥交换是以SSH_MSG_KEXINIT开始,SSH_MSG_NEWKEYS结束。密钥更新继续沿用旧的向量(加密密钥、初始向量、消息签名密钥),密钥交换后更新所有的向量。密钥更新过程可以改变服务端密钥、算法等,唯独Session Id不会更新。

7. 使用算法

算法选择和密钥交换后,客户端和服务端要开始使用所选择的算法了。正如报文封装图所示,发送数据包要进行压缩、填充、加密、校验四个步骤。当然,如果某一算法最终选择了none,可以跳过这一步骤。

  1. 压缩比较简单,调用选择的算法直接压缩原始数据包即可。
  2. 因为SSH支持的只有分组加密算法,所以必须对数据进行填充,以满足分组要求。SSH规定,最小数据数据分组为8个字节,至少要填充4个字节,最多填充255字节。填充后的数据格式是:压缩后数据长度(uint32)+填充长度(byte)+压缩后的数据+填充。
  3. 数据填充后,是8或者block size的整数倍,这样正好使用加密算法进行加密。无论选择哪种密码模式(CBC、CTR等),密钥更新周期内传递密钥分块参数。
  4. 校验数据的输入有数据包序号和加密后的数据。校验数据不进行加密直接附在密文后传递。

解密过程与上述过程正好相反。

8. 数据包封装

SSH的每个数据包都是以1个字节数据包类型标识打头的。接下来按照不同的数据包类型序列化或反序列化数据。需要另外考虑的是,一些类型的数据包结构是可变的。
例如,下面分别是固定结构的数据包和可变结构的数据包:

byte      SSH_MSG_DISCONNECT
uint32    reason code
string    description in ISO-10646 UTF-8 encoding [RFC3629]
string    language tag [RFC3066]

下面这个数据包后面的数据就根据request type的变化而变化。

byte      SSH_MSG_CHANNEL_REQUEST
uint32    recipient channel
string    request type in US-ASCII characters only
boolean   want reply
....      type-specific data follows

三、身份认证

客户端请求需要的服务前,需要向服务端表明身份。首先客户端发送SSH_MSG_USERAUTH_REQUEST,表明需要请求的服务和打算使用的身份认证方式(publickeypasswordhostbasedkeyboard-interactive等)。若服务端接受就直接返回SSH_MSG_USERAUTH_SUCCESS,这样客户端就不用发送任何身份认证数据证明我是我了。如果服务器觉得还需要进一步验明真身,会返回SSH_MSG_USERAUTH_FAILURE,并告知服务端支持的身份认证方式。接下来客户端与服务端大战100回合以证明“我就是我!”。

publickey为例说明:

  1. C:发送SSH_MSG_USERAUTH_REQUEST,表明使用none方式验明真身,企图不验证身份。
  2. S:发送SSH_MSG_USERAUTH_FAILURE,告知服务端只支持publickey方式认证。
  3. C:发送SSH_MSG_USERAUTH_REQUEST,乖乖使用publickey方式,并附上自己的公钥,不对自己的数据进行签名,企图瞎蒙一个公钥。
  4. S:发送SSH_MSG_USERAUTH_PK_OK,告诉客户端我可以接受你的公钥,但是你要证明你有私钥。
  5. C:发送SSH_MSG_USERAUTH_REQUEST,再次乖乖的把上次传输的数据用自己的私钥进行签名。
  6. S:心想,这货终于暴露身份了,去数据库里查查这货有没有来注册过。发送SSH_MSG_USERAUTH_SUCCESS告诉客户端你这个逗比,给你开通权限了。

上面任何一个过程出那么一小点差错,都会导致身份认证失败。虽然身份认证失败了,但是客户端可知耻而后勇,继续向服务端发起挑战。所以RFC建议客户端尝试一定次数后,要T掉这个逗比客户端。当然啦,如果客户端第一次就用自己的私钥对数据签名了,就会一次通过身份认证。

四、使用连接层服务

连接层服务可复用通道。使用前请求建立通道,用发送窗口控制传输速率,每个通道还可区分数据类型(stdio,stderr等),通道使用后进行关闭。连接层也比较复杂,通道有比较多的类型:sessionx11forwarded-tcpipdirect-tcpip等。

客户端首先会发送SSH_MSG_CHANNEL_OPEN数据包,请求开启session通道,同时也说明客户端的通道号、支持的窗口大小、支持最大数据包大小。服务端会返回SSH_MSG_CHANNEL_OPEN_CONFIRMATION数据包,确认打开通道,说明服务端的通道号、支持的窗口大小、支持最大数据包大小。这时候客户端和服务端已经知道了对方的通道号、窗口大小、支持的最大数据包大小。

然后客户端发送SSH_MSG_CHANNEL_REQUEST,确定session的类型。want reply字段表示客户端是否希望服务端进行回复,如果设置成true,服务端必须立即返回SSH_MSG_CHANNEL_SUCCESSSSH_MSG_CHANNEL_FAILURE或别的。exec会带上一条命令给服务端执行,而shell不会。现在,可双向传送数据的通道已经建立完毕。客户端和服务端必须在对方窗口空间用完后阻塞数据发送。所以客户端和服务端在收到一定量的数据之后要及时发送SSH_MSG_CHANNEL_WINDOW_ADJUST调整窗口大小。

任何一方数据发送完成后,可以发送也可不发送SSH_MSG_CHANNEL_EOF标记,服务端可以选择发送或不发送SSH_MSG_CHANNEL_REQUEST数据包返回exit-status。一方发送SSH_MSG_CHANNEL_CLOSE后就不能继续发送数据,但另一方还可以继续发送。双方都发送SSH_MSG_CHANNEL_CLOSE后,通道才算完全关闭。这一点类似TCP的半关闭状态

五、实现Git服务端协议

Git客户端与服务端可以用SSH通道连接,服务端根据客户端请求的命令,启动相应的进程进行交互。SSH只是起到了一个管道的作用。Git客户端在建立SSH连接后,请求session通道exec命令。建立管道的代码如下:

var git = new GitService(command, project);
e.Channel.DataReceived += (ss, ee) => git.OnData(ee);
e.Channel.CloseReceived += (ss, ee) => git.OnClose();
git.DataReceived += (ss, ee) => e.Channel.SendData(ee);
git.CloseReceived += (ss, ee) => e.Channel.SendClose(ee);
git.Start();

是不是非常非常的简单?

六、打个广告

为了写本文,专门用C#语言实现了SSH服务端。你可以在github上找到SSH服务端的源码,这个源码顺便实现了Git服务端的例子。我不会告诉你地址是:https://github.com/Aimeast/FxSsh

既然最后一段提到了实现Git服务端,本来不想告诉你我用C#实现了一个基于ASP.NET MVC的Git服务端,它的名字叫做GitCandy。现在已经支持http(s)ssh协 议访问了。据我所知,这可曾是全球第一个用C#实现的同时支持http(s)和ssh协议的Git服务端。我也不想告诉你,等到ASP.NET vNext发布后,GitCandy会同时支持Windows、Linux、Mac等操作系统。既然已经说了这么多不想说的话,那我就再多说一句 吧,GitCandy的源码在https://github.com/Aimeast/GitCandy,使用MIT授权协议。欢迎各位赏脸!

GitCandy交流QQ群:200319579。

[转载]用c#开发微信 (18) 多客服 - 疯吻IT - 博客园

mikel阅读(789)

来源: [转载]用c#开发微信 (18) 多客服 – 疯吻IT – 博客园

微信官方的多客服接口原理是通过用户发送的信息,开发者服务器返回一条指定类型的响应信息,使用户的对话状态切换到官方的多客服状态(持续一段时间),这段时间内用户发送的所有信息都不会到达开发者的服务器,而是转到多客服的软件上。

 

 

1 开通多客服

先开通微信认证;再从“功能”-》“添加功能插件“里选择“多客服”以开通多客服功能

 

2 添加客服工号

在“功能”-》“多客服”里添加客服工号:

image

 

 

3 启动多客服

3.1 在电脑上使用多客服接待

从上图中指示的位置下载多客服客户端,安装完后,用上面创建的客服工号登录多客服客户端

 

3.2 在微信上使用多客服接待

关注公众号”多客服助手“(duokefu)

关注后,再绑定客服工号

 

4 多客服开发

开发很简单,只用在CustomMessageHandler里的OnTextRequest方法里加上下面的代码即可:

if (requestMessage.Content == "人工客服")
{
    return this.CreateResponseMessage<ResponseMessageTransfer_Customer_Service>();
}

 

注意,不用改变此方法里原有的代码,只是添加上面的代码。不清楚这个方法的用法可参考《用c#开发微信(3)基于Senparc.Weixin框架的接收普通消息处理 (源码下载)》。

这段代码添加完成后,就基本实现了多客服功能了,只要微信用户给公众号发送“人工客服”后就可进入多客服状态,跟客服人员聊天了。

每次要微信用户输入这几个字有点麻烦,我们可以创建一个菜单,让用户点一下菜单就行了:

image

关于自定义菜单可参考《用c#开发微信(5)自定义菜单设置工具 (在线创建)

 

 

5 测试

用户点公众号里“人工客服”菜单,在多客服客户端就会出现“1人等待接入”,点击它后,出现未接入客户列表,勾选要接入的客户,然后点击“接入”

image

 

接入之后,就可以开始客服聊天了:

image

Screenshot_2015-06-18-08-03-52

 

测试了文字和图片完全没问题,但用户不能发语音和视频给客服,客服却可以发语音给用户:

image

 

另外,多客服客户端还可以实现下面的功能,大家可以试下:

  • 自动接入
  • 转接会话
  • 会话自动关闭(如5分钟用户没回复)
  • 接入提示语设置
  • 工号自动回复
  • 主号自动回复

 

 

 

C#开发微信 系列汇总

作者:疯吻IT 出处:http://www.cnblogs.com/fengwenit/ 转载请注明出处!

[转载]定制自己的firefox插件并在selenium中使用 - 刘邺 - 博客园

mikel阅读(810)

来源: [转载]定制自己的firefox插件并在selenium中使用 – 刘邺 – 博客园

首先搭建火狐插件开发环境:

然后编写一个简单的firefox插件

  • 先创建一个火狐插件工作空间,比如:d:\ff-addon-ws
  • 然后cd到”火狐sdk/bin”目录下,再打开一个新的cmd窗口,然后把activate这个文件拖到cmd窗口中运行
  • 然后cd到火狐插件工作空间,
  • 创建一个插件项目并初始化
  • 项目创建完成后编写插件具体实现,这里直接拷贝一段简单的代码.具体做法是进入刚刚创建的插件项目目录下的lib子文件夹,里面有一个main.js,然后把下面这段代码直接拷进去
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    var buttons = require('sdk/ui/button/action');
    var tabs = require("sdk/tabs");
    var button = buttons.ActionButton({
      id: "mozilla-link",
      label: "Visit Mozilla",
      icon: {
        "16": "./icon-16.png",
        "32": "./icon-32.png",
        "64": "./icon-64.png"
      },
      onClick: handleClick
    });
    function handleClick(state) {
      tabs.open("https://www.mozilla.org/");
    }
  • 由于这段代码使用了3张图片,所以在本文附加中下载下来然后放到插件目录下的data子文件夹中
  • 完成上面几个步骤之后就可以测试这个插件了,输入cfx run,如图:
  • 点击右边火狐小图标后会打开一个新的标签页转到火狐主页,到这里一个最简单的定制插件就完成啦!接下来就是打包成xpi,这样就可以安装到火狐浏览中

插件编写参考自:https://developer.mozilla.org/en-US/Add-ons/SDK/Tutorials/Getting_started

最后一步就是在selenium中使用了,没用过selenium的朋友可以不看下面的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
System.setProperty("webdriver.firefox.bin",
        "D:/Program Files (x86)/Mozilla Firefox/firefox.exe");
TemporaryFilesystem.setTemporaryDirectory(new File(
        "D:/workspace/firefox/seleniumTemp/"));
FirefoxProfile firefoxProfile = new FirefoxProfile(new File(
        "D:/workspace/firefox/profiles/test/"));
File cookieWriter = new File("rwfile.xpi");
try {
    firefoxProfile.addExtension(cookieWriter);
    //设置插件相关参数  参数格式为   extensions.插件名.参数名
    // 设置插件版本
    firefoxProfile.setPreference("extensions.rwfile.currentVersion",
            "1.0");
    //默认情况下通过selenium加载的插件是被火狐禁用的,设置下面几个参数就可以启用了
    firefoxProfile.setPreference(
            "extensions.rwfile.console.enableSites", true);
    firefoxProfile.setPreference("extensions.rwfile.net.enableSites",
            true);
    firefoxProfile.setPreference(
            "extensions.rwfile.script.enableSites", true);
    firefoxProfile.setPreference(
            "extensions.rwfile.allPagesActivation", "on");
} catch (IOException e) {
    e.printStackTrace();
}
WebDriver driver = new FirefoxDriver(firefoxProfile);
driver.get("http://www.xhalj.com/");

 

[转载]EasyUI实战经验总结,给有需要的人 - 淮左 - 博客园

mikel阅读(876)

来源: [转载]EasyUI实战经验总结,给有需要的人 – 淮左 – 博客园

最近公司培训EasyUI,就做下总结吧,给有需要的人,源码在文章最后。

1、最常用的表格

1
2
3
<div class="easyui-panel" data-options="region:'center'" style="padding: 20px">
     <table id="dg"></table>
 </div>

注意<table>标签,我们将利用这个标签进行表格加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
$("#dg").datagrid({
    //---------------------------- 属性 Properties ----------------------------
    //请求类型 默认post
    method: "get",
    //请求url地址 默认null
    url: "../../../json/grid.json",
    toolbar: [{
        iconCls: 'icon-add',
        handler: function () {
            alert("add");
        }
    }, {
        iconCls: 'icon-edit',
        handler: function () {
            //alert("edit");
            console.log($("#dg").datagrid("getChecked"), $("#dg").datagrid("getSelected"));
        }
    }, {
        iconCls: 'icon-remove',
        handler: function () {
            alert("remove");
        }
    }],
    //是否分页  默认false
    pagination: true,
    //分页的位置 默认bottom ['top','bottom','both']
    pagePosition: "bottom",
    //每页数量  默认10
    pageSize: 50,
    //每页页数控制 默认[10,20,30,40,50]
    pageList: [50, 100, 200, 500],
    //当前页 默认1
    pageNumber: 1,
    //列配置
    columns: [
    [{ field: 'DHOrderNo', title: "订货单编号", width: 100, halign: "center", align: "left", resizable: false },
        { field: 'TotalQty', title: "订单总数", width: 100, sortable: true, editor: "text" },
        {
            field: 'SupplierName', title: "供应商", width: 100, sortable: true,
            //格式化对象
            formatter: function (value, row, index) {
                if (value) {
                    return value.Name;
                }
            },
            //注意:如果该列数据源是Object需按以下方式排序
            //不一定要用显示的属性,也可以使用其他属性,看情况而定。
            sorter: function (a, b) {
                return a.Name == b.Name ? 0 : a.Name > b.Name ? 1 : -1;
            }
        },
        { field: 'CreateDate', title: "创建日期", width: 100, editor: "datebox" },
        {
            field: 'action', title: '操作', width: 70, align: 'center',
            formatter: function (value, row, index) {
                if (row.editing) {//编辑中
                    var s = '<a href="#" onclick="saverow(this)">保存</a> ';
                    var c = '<a href="#" onclick="cancelrow(this)">取消</a>';
                    return s + c;
                } else {
                    var e = '<a href="#" onclick="editrow(this)">修改</a> ';
                    var d = '<a href="#" onclick="deleterow(this)">删除</a>';
                    return e + d;
                }
            }
        }
    ]]
});

那么页面的效果是:

感觉easyui的界面还是蛮清爽的
这边的nav.json是一个json格式文件内容是
1
2
3
4
5
6
7
8
9
10
11
12
{
    "total":360,
    "rows":[
        { "DHOrderNo":1, "Funding": "资金方1","Number":2,"Unit":50,"TotalQty":100,"SupplierName":{ "Id":1, "Name":"供应商1" },"CreateDate":"2015-05-21","Flag":1 },
        { "DHOrderNo":2, "Funding": "资金方2","Number":5,"Unit":50.01,"TotalQty":250.05,"SupplierName":{ "Id":2, "Name":"供应商2" },"CreateDate":"2015-05-21","Flag":0 },
        { "DHOrderNo":3, "Funding": "资金方3","Number":10,"Unit":60, "TotalQty":600,"SupplierName":{ "Id":3, "Name":"供应商3" },"CreateDate":"2015-05-21","Flag":1 }
    ],
    "footer":[
        { "Funding":"平均","TotalQty": 316.68 },
        { "Funding":"总和","TotalQty": 950.05 }
    ]
}
2、表格扩展,下面是扩展的写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    $.fn.ProductGrid = function(options, param) {
    var me = this;
    //判断options是否是string类型
    if (typeof options == 'string') {
        //根据options从datagrid的配置中查找
        var method = $(this).datagrid('options')[options];
        //如果没找到,从$.fn.ProductGrid的methods中查找
        if (!method)
            method = $.fn.ProductGrid.methods[options];
        //如果存在,调用方法
        if (method)
            return method(this, param);
        else
            alert(options + 'can not support');
    }
    var defaults = {
        url : options.url,
        method : 'get',
        border : false,
        singleSelect : true,
        fit : true,
        fitColumns : true,
        //附加的公共方法
        searchByPage : function(jq, id) {
            alert('this is public function!');
            $(me).datagrid('load', {});
        },
        columns : [ [
            {field:'DHOrderNo',title:"ID",width:80},
            {field:'Funding',title:"资金方",width:100},
            { field: 'TotalQty', title: "数量", width: 80 }
        ]]
    };
    options = $.extend(defaults, options);
    $(me).datagrid(options);
};

2、表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<form id="form" method="get">
    <table>
        <tr>
            <td>姓名:</td>
            <td><input class="easyui-validatebox" type="text" name="name" data-options="required:true"></input></td>
        </tr>
        <tr>
            <td>Email:</td>
            <td><input class="easyui-validatebox" type="text" name="email" data-options="validType:'email'"></input></td>
        </tr>
        <tr>
            <td>备注:</td>
            <td> <textarea name="message" style="height:60px;"></textarea></td>
        </tr>
        <tr>
            <td>年龄:</td>
            <td><select name="age" class="easyui-combobox" >
                <option value="1">20~30</option>
                <option value="2">30~40</option>
                <option value="3">40以上</option>
            </select></td>
        </tr>
        <tr>
            <td>日期:</td>
            <td><input class="easyui-datebox" name="date" /></td>
        </tr>
        <tr>
            <td>数字:</td>
            <td><input class="easyui-numberbox" name="number" /></td>
        </tr>
    </table>
    <div>
        <a id="load" class="easyui-linkbutton" href="JavaScript:">加载本地数据</a>
        <a id="load2" class="easyui-linkbutton" href="JavaScript:">加载ajax数据</a>           
        <a id="submit" class="easyui-linkbutton" href="javascript:">提交</a>
        <a id="clear" class="easyui-linkbutton" href="javascript:">清空</a>
    </div>
</form>

对应的js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$("#submit").on("click",function(){
     $('#form').form("submit",{
         url:"../../json/submit.json",
         onSubmit:function(pParam){
             //附加表单以外的一些验证
             //通过pParam附加一些提交参数
             pParam.index = 1;
             return $('#form').form("validate");
         },
         success:function(data){
             alert(data);
         }              
     });
 });
 $("#clear").on("click",function(){
     $('#form').form("reset");
 });

注意表单中的easyui属性,运行的效果如:

 

3、树,直接看代码吧,代码有注释

1
2
3
4
5
6
7
8
9
10
     $("#tree").tree({
    url:"json/nav.json",
    method:"get",
    lines:true,
    onClick:function(node){
        if(node.url && node.url.length > 0){
            _this.add(node.text,node.url,node.id,node.icon);
        }
    }
});

 

数的json文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[
    {
        "id":101,"text":"2、表单",
        "children":[
            { "id":2, "text": "2.1、简单示例", "url":"views/form/form.html" },
            { "id":3, "text": "2.2、常用示例", "url":"views/form/forms.html" }
        ]
    },{
        "id":102,"text":"3、表格",
        "children":[
            { "id":4, "text": "3.1、简单示例", "url":"views/grid/grid.html" },
            { "id":5, "text": "3.2、明细示例", "url":"views/grid/gridDetail.html" },
            { "id":6, "text": "3.2、行编辑示例", "url":"views/grid/edit.html" },
            { "id":6, "text": "3.2、表格编辑示例", "url":"views/grid/edit2.html" }
        ]
    },{
        "id":103,"text":"4、树",
        "children":[
            { "id":4, "text": "4.1、简单示例", "url":"views/tree/tree.html" },
            { "id":5, "text": "4.2、示例", "url":"views/tree/treeGird.html" }
        ]
    }
]

如果把这个文件放在vs中,运行index.html时候回报错,请在web.config中配置,才能识别.json文件

1
2
3
4
5
<system.webServer>
   <staticContent>
     <mimeMap fileExtension=".json" mimeType="application/json" />
   </staticContent>
 </system.webServer>

源码地址:http://pan.baidu.com/s/1gdH8CCj

EasyUI的中午文档 和学习网站

http://www.zi-han.net/case/easyui/index.html

http://www.jeasyui.net/demo/380.html

网站不赚钱的原因

mikel阅读(901)

网站不赚钱的原因很多,但是最根本的原因只有一个,那就是太过高估了自己的网站价值了。

很多站长都觉得建个地方论坛,就可以垄断地方的流量,成为号令一方的诸侯了,可惜从建站到推广一直都是自我欣赏式的运营,结果流量来了又走,不但赚不到钱还赔了自己的打好时光。

有的站长走得是跟风路线,看到别人的网站火了,就去模仿,结果不知市场已经早就尘埃落定,再多的加入者也只是捡些残羹剩饭而已。看到贼吃饭,没见过贼挨打,人家挨打的时候你还在模仿别的网站呢!没有坚持精神很难做好一个事儿。

然后就是神话了SEO和推广,认为有流量就有钱,这对于过去的门户时代好使,现在只能说你太高估自己了,网络上网站上亿,你推广来的访问者看到没有新意的网站,直接关闭了走人,网民相比过去越来越没有耐心,哪怕你有新意的网站,不是他需要的,也只是一次访问就不会再光顾了,听起来挺让人心寒,没办法现实就是这样。

总结了这么多,还是有很多站长赚钱的,究其原因就是脚踏实地与时俱进的寻找适合自己的盈利模式,有些人推VIP服务,赚少数人的钱,就活得很好,等等,所以说做网站没有创新就是死。