Git Product home page Git Product logo

geminiwen.github.io's People

Contributors

geminiwen avatar

Stargazers

 avatar  avatar

Watchers

 avatar

Forkers

swillk

geminiwen.github.io's Issues

Android UriMatcher

UriMatcher使用的算法是不是属于编译原理的范畴不知道。
但是这段简短的源代码看着真心很舒心。
用了树的一些数据结构,从子树中找token。
只是很感兴趣,所以摘抄一下,但是我感觉它写的并不是特别好看

public class UriMatcher
{
    public static final int NO_MATCH = -1;
    /**
     * Creates the root node of the URI tree.
     *
     * @param code the code to match for the root URI
     */
    public UriMatcher(int code)
    {
        mCode = code;
        mWhich = -1;
        mChildren = new ArrayList<UriMatcher>();
        mText = null;
    }

    private UriMatcher()
    {
        mCode = NO_MATCH;
        mWhich = -1;
        mChildren = new ArrayList<UriMatcher>();
        mText = null;
    }

    /**
     * Add a URI to match, and the code to return when this URI is
     * matched. URI nodes may be exact match string, the token "*"
     * that matches any text, or the token "#" that matches only
     * numbers.
     *
     * @param authority the authority to match
     * @param path the path to match. * may be used as a wild card for
     * any text, and # may be used as a wild card for numbers.
     * @param code the code that is returned when a URI is matched
     * against the given components. Must be positive.
     */
    public void addURI(String authority, String path, int code)
    {
        if (code < 0) {
            throw new IllegalArgumentException("code " + code + " is invalid: it must be positive");
        }
        String[] tokens = path != null ? PATH_SPLIT_PATTERN.split(path) : null;
        int numTokens = tokens != null ? tokens.length : 0;
        UriMatcher node = this;
        for (int i = -1; i < numTokens; i++) {
            String token = i < 0 ? authority : tokens[i];
            ArrayList<UriMatcher> children = node.mChildren;
            int numChildren = children.size();
            UriMatcher child;
            int j;
            for (j = 0; j < numChildren; j++) {
                child = children.get(j);
                if (token.equals(child.mText)) {
                    node = child;
                    break;
                }
            }
            if (j == numChildren) {
                // Child not found, create it
                child = new UriMatcher();
                if (token.equals("#")) {
                    child.mWhich = NUMBER;
                } else if (token.equals("*")) {
                    child.mWhich = TEXT;
                } else {
                    child.mWhich = EXACT;
                }
                child.mText = token;
                node.mChildren.add(child);
                node = child;
            }
        }
        node.mCode = code;
    }

    static final Pattern PATH_SPLIT_PATTERN = Pattern.compile("/");

    /**
     * Try to match against the path in a url.
     *
     * @param uri       The url whose path we will match against.
     *
     * @return  The code for the matched node (added using addURI), 
     * or -1 if there is no matched node.
     */
    public int match(Uri uri)
    {
        final List<String> pathSegments = uri.getPathSegments();
        final int li = pathSegments.size();

        UriMatcher node = this;

        if (li == 0 && uri.getAuthority() == null) {
            return this.mCode;
        }

        for (int i=-1; i<li; i++) {
            String u = i < 0 ? uri.getAuthority() : pathSegments.get(i);
            ArrayList<UriMatcher> list = node.mChildren;
            if (list == null) {
                break;
            }
            node = null;
            int lj = list.size();
            for (int j=0; j<lj; j++) {
                UriMatcher n = list.get(j);
          which_switch:
                switch (n.mWhich) {
                    case EXACT:
                        if (n.mText.equals(u)) {
                            node = n;
                        }
                        break;
                    case NUMBER:
                        int lk = u.length();
                        for (int k=0; k<lk; k++) {
                            char c = u.charAt(k);
                            if (c < '0' || c > '9') {
                                break which_switch;
                            }
                        }
                        node = n;
                        break;
                    case TEXT:
                        node = n;
                        break;
                }
                if (node != null) {
                    break;
                }
            }
            if (node == null) {
                return NO_MATCH;
            }
        }

        return node.mCode;
    }

    private static final int EXACT = 0;
    private static final int NUMBER = 1;
    private static final int TEXT = 2;

    private int mCode;
    private int mWhich;
    private String mText;
    private ArrayList<UriMatcher> mChildren;
}

其实主要看 addURImatch 两个函数

思考

好些天没来Github上逛逛了。
这些天算是给自己放了一个小假。
因为没有深入学习知识,到了第一个瓶颈,就忘了前进的方向了。
真的是很糟糕的一件事情。
为了让女朋友能好好考过四级,就买了一台13英寸的yoga给她,希望真的能好好用起来吧,想想以前爸爸妈妈对我的是不是就是这样的感觉。
无地自容啊。
听了几个屌丝逆袭的故事,还有高富帅天生高人一等的故事。
不会觉得自己高不成低不就,而是一直不行啊。
算了,继续努力呗。作为底层人民 你还有什么办法。
技不如人啊。
加油吧,发点牢*,然后睡觉了

CSS3 box-sizing

今天看了github User Page的一些指南,
然后创建了http://coffeesherk.github.com 的repo。因为自己比较懒,想用点metro风格的东西,就屁颠屁颠地跑到微软官方网站上盗窃风格了。
因为对前端的东西一直是很感兴趣,但是对于CSS3的东西从来没有涉及。今天看到一个属性叫做box-sizing。解决了自己的问题,同时也看到了一篇很不错的文章
看了大半段东西(原谅我英文不好,只能一直拿着有道翻译)
其实最最重要的应当是这幅图
widthbox
设置为

box-sizing: border-box;
-moz-box-sizing:border-box; /* Firefox */
-webkit-box-sizing:border-box; /* Safari */

就可以严格按照第二幅图的盒模型了。
w3schools上对box-sizing是这么描述的
The box-sizing property allows you to define certain elements to fit an area in a certain way:
其实这个certain 我查了半天是当然的意思。。看完文章 也感觉。。好直截了当的翻译。好吧 我就翻译为严格按照width来进行衡量。
总之,挺不错的,一个小知识,记住了。

2013-8-26

这两天有些疲软。
想好的每天在家看书,也没有达成愿望。
因为自己的一些原因思绪有点乱。
下周可以见着女朋友,很开心。
所以现在还是在期待的样子。
这些天当调整或者休息吧。
一直紧绷着神经受不了了。
所以,随便翻翻书还是怎么的都可以。
希望快乐。加油。

jQuery中的Data对象

jQuery中对每个对象都会做一定的数据缓存
具体看jQuery中的Data对象。
对一个对象设置一些缓存值的时候,首先会检测缓存中是否已经存在这个对象,如果不存在这个对象,则给该对象分配一个non-enumerable的一对k-v 其中k为一串随机字符串(在整个jQuery生命周期中唯一),v是一个全局的uid,用来标识这个对象。然后在一个全局cache中,使用这个uid作为键,得到其对应的cache数组。
好吧,这里的确有一些饶,那么用一些图例表达,就是这样的:

待缓存对象 Object o;

// 这部分给这个o设置了一个uid
// get key function:
var key = function( o ) {
    if ( o [ jQuery.expando ] === undefined ) {
        o [ jQuery.expando] = jQuery.uid ++;
    }
    var key = o [ jQuery.expando ];
   if(!cache[key] ) {
       cache[key] = {};
   }
    return o [ jQuery.expando ];
}
var set = function(o,k,value ) {
    // get the key from it's properties
    var cache = key(o);
    cache[k] = value;
}

这一段缓存还是挺取巧的办法

jquery live -> on

旧版jquery中的live函数

曾经看到旧版的jquery api中有一个事件绑定的live函数,它的特点就在于符合选择器(selector)的后加入的子孙结点也能被抓住事件。但是后来被deprected掉了,live,delegate函数都不见了,在jquery2.0.0时代(当然是之前,我是指我用的版本)使用on函数去绑定。

on函数中的selector

on函数的原型是

.on( events [, selector ] [, data ], handler(eventObject) )

这其中有一个selector一开始并不明白,设计的模式是将事件绑定在这些后来加入结点的父节点上。

$(parent).on('click','child',function(){...})

就是这样的形式,这样,符合selector child 的各种元素 都能获得事件。

这里就讲用法,具体实现还是要看jquery源码的。当然我还没看,哈哈哈

seajs id2uri 笔记

在列车上实在无聊,本地存有seajs源代码,想想今天的目标是看明白id2Uri的路径解析,所以就去看看了。id2Uri调用一般是在Module.resolve中的。seajs中的一次代码提交就是把Module.resolve这个接口暴露出来,提供对脚本高效率的解析。

id2Uri 解析步骤

首先看id2Uri的源码

function id2Uri(id, refUri) {
  if (!id) return ""

  id = parseAlias(id)
  id = parsePaths(id)
  id = parseVars(id)
  id = normalize(id)

  var uri = addBase(id, refUri)
  uri = parseMap(uri)

  return uri
}

很偷懒地没有写出详细的解析过程。不过从这几个函数的名字可以看出它的大致步骤。
四个步骤分别是

  1. 别名解析(如jquery)
  2. 路径重定向
  3. 路径中的变量解析
  4. 标准化路径

seajs config中的别名设置可以在这里首先得到解析,然后是path重定向的路径解析,然后是变量解析,最后是标准化的路径(就是把文件后缀名加上)。

转换成完整路径

addBase是将相对路径组成一个完整路径。
最后是config中设置的路径映射(这里好像是debug插件也有用)

这样就组成了完整的路径,可以被seajs 调用fetch方法得到模块了。

seajs的路径解析模块就到这了~唯一非人可以阅读的就是解析require中字符串的那一大堆正则。当时拔赤有一个PPT讲框架获取DOM结点速度非常慢,因为好奇我去看了一下一些框架(如jQuery)的解析过程。显然有一步是需要将字符串中的元素利用正则去提取,然后再调用document.getElement(s)系列的方法得到DOM结点,这里我猜想正则的处理速度肯定不是特别快,有机会再去实践一下。

约瑟夫环小记

约瑟夫环小记

说起约瑟夫环,记得很有激情的那会,在某次英语模拟考上,直接想约瑟夫环推导过程了,但是由于数学不好,想了90分钟都没想出来,哎~反正就是算了。今天看了下,居然就理解了,这是年龄问题吗?问题吗?吗?

#include "stdio.h"
#include "stdlib.h"

int josephus(int n, int m)
{
    int pos;
    if (n == 1) {
        return 1;
    } else {
        pos = (josephus(n-1, m) + m -1)%n + 1;
    }

    return pos;
}

int josephus_no_recurse_1(int n, int m)
{
    int s = 0;
    int i;
    for (i=2; i<=n; i++) {
        s = (s + m)%i;
    }
    return s + 1;
}

int josephus_no_recurse_2(int n, int m)
{
    int s = 1;
    int i;
    for (i=2; i<=n; i++) {
        s = (s + m -1)%i + 1;
        if (s == 0) {
            s = n;
        }
    }
    return s;
}

全篇文章见
http://blog.csdn.net/zhengkarl/article/details/5596118
主要过程:

序列三:k+1, k+2, k+3, …, n-2, n-1, n, 1, …, k-2, k-1
序列四: 1 , 2 , 3 , …,n-k-2, n-k-1, n-k, n-k+1, …,n-2, n-1 (这里就是把名字换一下)
k是第一轮中被取出的数,x为序列四中的解,x'是序列三中的解
又∵ k = m%n;
∴ x' = x+k = x+ m%n ; 而 x+ m%n 可能大于n
∴x'= (x+ m%n)%n = (x+m)%n

为什么x' = x + k呢。。
因为原来 1...n 个人 去掉第k个人后
序列变成 k+1 k+2 k+3 ...n 1.. k-1
序列四是 1 ,2 ,3 ... n-1
k+1 -> 1
k+2 -> 2
k+3 -> 4
∴ k + x -> x'
但当x'<k时x'=x+k-n
所以 推出来:x'=(x+k)%n

x‘=(x+k)%n,由此,我们可以得到一个递推公式
f[1]=1
f[n]=(f[n-1]+k)%n (n>1)
如果你认为上式可以推出约瑟夫环问题的解,很不幸,你错了,上面的递推公式中,在某种情况 下,f[n-1]+k会整除n,如n=2,k=3,这时我们修要对上式进行修正,
f[n]=(f[n-1]+k)%n;if(f[n]==0)f[n]=n;
问题得解

Rescure

最近状态一直不佳。
处于自我否定自我肯定自我否定自我肯定的切换中。
买了一本《大话设计模式》
看得还算起劲。
也算明白了很多以前没看懂的设计模式。

一直想从质量上有所进步。
现在看来还有很长的路要走,总是没有那么细心和耐心,想想这样就算了。
这样到底是对的还是错的。

jQuery 选择器浅析

由于水平原因,只能用浅析这个词啦~
上次我谈到javascript中constructor的返回值问题#35 我首先就是在jQuery选择器函数中看见的。也就是大名鼎鼎被winter大神吐槽死的$函数
这里我们谈到的jQuery版本是2.0.3
http://code.jquery.com/jquery-2.0.3.js
首先最简单的那个选择符号是#id和标签tag,它使用jQuery中的rquickExpr正则表达式来判断的。如果满足正则表达式,则使用 getElementById 或者 getElementsByTag 的方法来获取元素。.class这种是使用Sizzle 选择引擎,其实它对这方面的操作也是使用正则进行,如果是.class就利用 getElementsByClassName 进行。jQuery.find这个静态方法就是被赋值成Sizzle的。
还有两种就是 $(document)$(function(){});
以前在学校的时候,以为 $(function(){}) 是立即执行的,昨天看了下源码才知道它是等效于 $(document).ready(function(){});
至于 $(document)嘛,就是直接返回啦,其实不只document,element也是,这里对这些结点的判断是根据nodeType来的。我也终于知道什么叫plainObject 真朴素~哈哈。
好了,晚安。

sea.js 模块加载和执行步骤

seajs是由玉伯开发的模块加载器
seajs模块加载的步骤分为模块文件加载,模块文件执行。
首先,文件加载之后,得到这个文件的依赖,将其放到缓存中去加载,当所有依赖的模块加载完成时,就执行factory函数,执行该模块的内容,下面尽我所能,把这一个流程讲清楚。

Seajs 递归加载入口

这个入口就是seajs.use函数了,产生一个模块叫"use",依赖于你所传入的参数。解析好这个参数(解析依赖路径的函数是id2Uri),把它cache起来,等待fetch。

Fetching module

得到模块的路径后,通过script标签将模块从服务器上下载过来(这里物理上单指文件)下载后的模块类似jsonp一样,先执行define函数。define函数如果是三参数的话就很轻松地能得到id、deps依赖数组、factory模块生产函数。如果是单参数的话,就需要一些正则去解析生产函数中的require函数。(所以!三参数的文件可以被uglify压缩而单参数不行!至于为什么,请自行看define函数)

Module loaded

模块加载完成后,触发模块onload事件,onload 将会递归调用。确保所有模块加载完毕。

Module execute

如果最上级模块依赖的所有模块都加载完毕,就开始执行factory函数,factory中的require函数将依次继续递归下去获取模块。

Margin Collapse

其实昨天才把自己定位成前端,也许就这么定位一下吧,虽然我很不喜欢定位自己:P,但是有时候真的是必要的。所以,阿温先森现在是Mobile Web Front-End。

今天要说的东西就是看Winter的Blog里面讲到一个名字 Margin Collapse。为此,不懂英文的我还去查了下词典,边框塌陷 当作翻译?好吧,不管翻译成什么,反正情况就是,在写某块内容的时候,margin不见了~ 专业名词就是塌陷了。

我看了下一篇文章。提取出发生塌陷最最关键的行为。那就是touch 当然这个只发生在top和bottom的margin中。

最简单情况

最简单的情况,就是并行的两个div 上下都设置了margin,如以下代码

<div style="margin:10px 0 10px 0">
test
</div>
<div style="margin:15px 0 15px 0">
test2
</div>

这里可以看见test和test2的上下边框有touch(可以理解为触碰),他们之间的margin就会发生塌陷,这其中的margin应当是按较大的算(也就是test2的margin-top当作test和test2之间的间隔)

margin为负数的计算

关于margin是负数的话,见文章中一个例子
它定义默认 p具有的上下margin是16px

<p style="margin-bottom:-5px;">A</p>
<p style="margin-top:100px;margin-bottom:-50px;"></p>
<p>B</p>

这里的计算流程是这样的:

  1. Work out what margins are touching.
  2. Ignore all negative margins.
  3. Perform the collapse as if there were no negative margins.
  4. Select the largest of the negative margins, and subtract it from the computed margin from step 3.

翻译下:

  1. 首先看下哪些margin会touch
  2. 然后无视所有的负数的margin
  3. 然后把那些计算出touch的margin进行塌陷
  4. 然后计算绝对值最大的负数的margin,然后将3中计算出的margin减去这个绝对值,得到的就是最终的结果

父子margin collapse的计算

父子的margin 产生touch的话,塌陷的优先级是越往外优先级越高,外部的margin进行塌陷,然后用里面的margin进行替代,换言之,如果子div元素背景是蓝色,父div元素背景是红色,塌陷后,红色的背景就会看不见了

解决塌陷的办法

原理很简单,就是让他们的margin不再接触就可。要么使用border隔开,要么使用padding隔开,当然使用overflow:hidden的原理是创建一个BFC,使得子div和父div处于不一样的BFC下,不同的BFC之间不存在touch(你可以理解为二次元的人和三次元的人握手,能成功么)也就不存在 margin conllapse

Seajs 和 RequireJS异同

这几天忙死啦,加班加了一周,几乎要崩溃了。
还好今天终于改完发现的BUG。可以完结了。
今天因为想分享Seajs的一些源码,所以趁早看了下seajs和requirejs的异同。
归纳完也只有几句。
模块都是 提前 加载
seajs是在require的时候执行,
requirejs是在加载完后就执行。

这是最大的区别。

顺便吐槽 装逼起码逼格要高,不然要被笑话~
发誓 接下去的产出,质量第一 学习自动化测试

好生蛋疼的KMP

啊!KMP

啊!July大神,膜拜。
http://blog.csdn.net/v_july_v/article/details/7041827
KMP算法的确是太奇妙了,我这笨脑子一天都还没想明白其中怎么回事,但是我已经会写这个模板了。苍天啊,悲剧啊。
首先,默写一段查找next数组的模板

void find_next() {
     int i,j = -1;
     i = 0;
     next[0] = -1;
     while(i<len) { //len : length of pattern string
          if( j == -1 || pattern[i] == pattern[j] ) {
                  i++; j++;   // 这里 i++ j++的意思就是 模式串中前面匹配部分的前缀和后缀都一样啦,那么只用从前缀的后一个字符开始匹配就好啦
                  if( pattern[i] == pattern[j] ) {  //当然 如果前缀的后一个字符和后缀还是一样的话,继续找前缀中的前缀吧(证明前缀中也是拥有一个k长度的前缀和后缀的)
                         next[i] = next[j];
                  } else {
                         next[i] = j; // 否则的话 就尝试匹配前缀的下一个字符吧
                  }
          } else {
                  j = next[j];  // 其实最搞不懂的就是这里啦。严蔚敏老师的数据结构书上说,这里的模式串就是待匹配串,当然j前面的东西都是拥有next数组的(因为之前计算过呀),所以可以拿来直接当kmp用。。。好吧暂时这么理解。
          }
     }
}

这个就是求next数组优化后的整个过程 在while循环体内if部分我都看得懂,else部分感觉莫名奇妙的。
不过它的确是自我匹配的过程,只是前缀后缀我头晕了T T


今天早上又想了想这个else里面的东西。
next[j] 在这之前已经算好,即可认为0...j 为模式匹配串,所以可以用next[j]

dijkstra + heap 最短路

我了个大擦。我需要宣泄一下,一开始完全不知道自己为什么会RE,提示SIGKILL,还去查了信号量的意思。楼下有人评论说是内存超了,是自己经验不足 ,完全不知道哪里内存超了,写了好多代码 和别人的比了下,甚至几乎完全自己抄了一遍 终于知道了是我的简单邻接表map[MAX][MAX]超了。不理解人家的linux环境全局变量分配只有那么少啊那么少。后来用了vector之流终于搞定了。原来用的思路还有很大优化的地方。
基本思路
http://blog.csdn.net/v_JULY_v/article/details/6274836

优化方法是,不需要每次都去build_heap。而是可以类似DFS BFS之流,在一开始初始化好一个堆(其实就是数组),每次把相邻的点加入到堆中,并尝试将该结点往根结点移动。如果已经在堆中的话。松弛后就直接尝试往根结点移动。
获取最小堆中最小的元素的时候,把数组中最后一个元素替换到根节点,然后尽量把大结点往下移动。这里可以见#13 介绍的堆排序操作。
贴上AC过的代码
题目是:http://www.spoj.com/problems/SHPATH/

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
#define MAX 10005

typedef pair<int,int> pii;
typedef vector<pii>::iterator iter;
vector<pii> road[MAX];
map<string,int> namemap;
//int mmap[MAX][MAX];
int dist[MAX];
int heap[MAX];
int hhash[MAX];//这个hash代表的意思是 指定的结点在堆中的位置
int heapSize;


void trylo(int u) { // 尝试把结点往下移动
    int tmp = heap[u],i = u;
    while (i*2+1<heapSize) {
        int j = i*2+1;
        if (dist[heap[j+1]]<dist[heap[j]]) j++;
        if (dist[heap[j]]<dist[tmp]) {
            heap[i] = heap[j];
            hhash[heap[i]] = i;
            i = j;
        }
        else break;
    }
    heap[i] = tmp;
    hhash[heap[i]] = i;
}

void tryhi(int u) { //尝试把结点往根结点移动
    int tmp = heap[u],i = u;
    while (i>0) {
        int j = (i-1)/2;
        if (dist[tmp]<dist[heap[j]]) {
            heap[i] = heap[j];
            hhash[heap[i]] = i;
            i = j;
        }
        else break;
    }
    heap[i] = tmp;
    hhash[heap[i]] = i;
}

void push(int u) { //加入堆
    heap[heapSize] = u; hhash[u] = heapSize++;
    tryhi(heapSize-1);
}

int extra_min() {
    int ret = heap[0];
    hhash[heap[0]] = -1;
    heap[0] = heap[heapSize - 1];
    hhash[heap[0]] = 0;
    heapSize --;
    trylo(0);
    return ret;
}

void dijkstra(int source,int to,int size) {
    memset(dist, 127, sizeof(dist));
    dist[source] = 0;
    heapSize = 0;
    int cost,v;
    int j;
    memset(hhash,-1,sizeof(hhash));
    push(source);
    while(heapSize) {
        int u = extra_min();
        /*
        for( j = 0; j < size; j ++ ) {
            v = j;
            if((dist[v] > dist[u] + mmap[u][v] ) && (mmap[u][v] != -1) ){ 
                dist[v] = dist[u] + mmap[u][v];
                if(hhash[v] == -1) push(v);
                else tryhi(hhash[v]);
            }
        }
        */
        for(iter i = road[u].begin(); i != road[u].end(); i++ ) 
        {
            v = i->first;
            cost = i->second;
            if( dist[v] > dist[u] + cost ) { //松弛的时候,因为没有=号,所以已经松弛到最优的结点自然不会进入到堆中,所以其实不需要标记也没有关系,省出一部分空间。
                dist[v] = dist[u] + cost;
                if(hhash[v] == -1) push(v);
                else tryhi(hhash[v]);
            }
        }

    }
    printf("%d\n",dist[to]);
}

int main() {
    int test,cities,maps,costs;
    char cityname[11],from_city[11],to_city[11];
    int i,j;
    int n_from,n_to,infos;
    scanf("%d",&test);
    while(test--) {
        //memset(mmap,-1,sizeof(mmap));
        scanf("%d",&cities);
        for(i = 0; i < cities; i++ ){
            road[i].clear();
            scanf("%s%d",cityname,&infos);
            namemap.insert(make_pair(string(cityname),i));
            for(j = 0; j < infos; j++ )
            {
                scanf("%d%d",&maps,&costs);
                road[i].push_back(pii(maps-1,costs));
                //mmap[i][maps-1] = costs;
            }
        }
        scanf("%d",&j);
        for(i=0;i<j;i++) {
            scanf("%s%s",from_city,to_city);
            n_from  = namemap[string(from_city)];
            n_to    = namemap[string(to_city)];
            dijkstra(n_from,n_to,cities);
        }
    }
    return 0;
}

jQuery 事件处理初出茅庐

最近无聊,以及私人的一些事情变动,或者也许心情原因,没有做任何和代码有关的东西。
上了另外一个QQ,有些话,说到嘴边,不想说了。
话讲多了,今天就粗略看了下jQuery的源代码,只是关于事件绑定的。
而且是没有selector和没有data的。
也就是形式如 on('click',function(){ }); 这样的处理过程。
那么首先jQuery选择器对元素的选择看 #36

选择过后,那么得到的是一个伪数组,对每一个数组调用jQuery.event.add函数,绑定一个EventHandler 将element和EventHandler缓存起来。然后在触发的时候,产生一个代理,这个代理去检测jQuery特有的事件,并且根据selector进行相关的事件的触发,一旦事件没有被终止,便一直传递下去。

jQuery在近端时间,源码全部转成AMD模式了,使用AMD模式,可能会更加清晰(我还不太会看源码,所以感觉被绕来绕去啊~毕竟文化不同,所以看英文的名字就有点点吃力)。

慢工出细活,js的部署还需要多去学习,就好像写好看的代码一样,我到现在也没有很好地能部署出一个OK的项目。。

关于自己

其实真的觉得,自己的纠结心情可以写本书了。
被媳妇吐槽了千万遍,一个男人怎么可以纠结至此。
归结为一个原因,看不见未来,没有安全感。

安全感从哪里来?

此时此刻我才开始想这个问题。
昨天在绍兴,无聊看《非诚勿扰》,一个女嘉宾如是说:“你自己都给不了你自己安全感,别人又怎么给你”。看上去像悖论的东西,我却不知道怎么反驳。是啊,安全感自始至终是自己给予自己的。
经济上,心理上,各式各样的安全感全部靠自己双手创造,我每次都是激励自己,激励成功后,不知道被什么东西打退回来了。想起来之后就很懊恼。过了很久之后,又会有新的东西来激励自己,周而复始。

关于技术专注

似乎所有人都和我讲专注于技术是极好的。我也许也知道,只是不肯相信。就像高中初中那会,叛逆不听话一样,也许也是不肯相信。黎叔今天和我说,三年内做一个这个行业的专家,否则就是一事无成。好像是一条铁律,我却没有任何成绩任何证据去打败这一个经验之谈。我并不是对技术不“专注”,而只是对于所有的技术都报有很大的好奇心。从前是这样,现在还是这样。当我碰壁的时候,也会去想着解决,同时所有的技术精力投入就被分散了。是的,的确是这样,这也是我最累的地方。它成为我最大的绊脚石。也许我真该好好静一静,告诉自己什么才是我需要的吧。

关于未来和目标

对于未来,现在的我真的很迷茫。比我强大经历比我少的人太多太多,不知道什么成就了他们,也不知道什么堕落了我。我只能奋起直追,用各种方法。未来是怎么样的,虽然我不知道,但是如果还是像昨天今天一样,狼狈不堪,堕落不前,那么它必定是不好的。

Gemini 同学,抓紧时间加油了。吃下,咽下,你想要的一切,在他到来之前,必将苦我心智,牢我筋骨。

跨域技术小记

这段时间,使用PhoneGap搭建移动端以来,碰到的最大的问题莫过于 跨域
跨域在从前最常用的应该有两种方式,自从HTML5发展之后,就变为了三种
分辨是

  • JSONP -- script标签跨域
  • Flash -- 挺强大,可惜移动端不支持,而且需要服务器放置crossdomain.xml文件
  • CORS -- 仅高端浏览器支持,带webkit浏览器内核的手机似乎很OK

前面两种已经让我尝试过,今天在http://coffeesherk.github.io 上做了第三种的测试。似乎一切都很简单,只用在ajax的url上使用带http协议的完整路径就行了。至于github api什么时候支持CORS的我已经忘记了,反正我当初建立这个repo的时候肯定是不支持的。不然我也不会学习这么个过程啦~说说每个技术的使用感受吧

JSONP

JSONP跨域的方式是使用script这个标签,向服务器发送一个请求,服务器在response中,为返回的请求加上请求中相应的参数,使用一种取巧的办法获取数据。它并不是一个新的技术,但是它是一种很棒的想法。你不能说它不好,因为有可能在没有JSONP的时候,你是想不到这个办法的~

Flash

Flash跨域只能适用于桌面浏览器,因为移动浏览器都不支持flash。而且flash编程绝对不适合我这种懒货,记得我为了调整它的权限问题,加了各种稀奇古怪的参数,最后好像还是因为缓存问题不能执行,因为我发现它在chrome中不行,在firefox中却可以跑了。而且在ie中,貌似flash的加载还是异步的(也许是chrome中比较快吗?)这造成了许多不可避免的奇怪的BUG。除此之外,还得在服务器中加个跨域策略才能搞定通信。强大但是不方便。

CORS

对于CORS(Cross Domain Resources Share),除了对老版本浏览器不兼容意外,它理所当然地成为了我最喜欢的一种跨域方式,它不是用小技巧(JSONP),也不是用一种奇怪的plugin方式提供支持(FLASH),它利用HTTP原生的一些属性,几乎是无缝地完成了升级(额。无缝不包括兼容性吧?好吧,还是有点缝的),使用HTTP协议中的Header域,添加一些字段,就完成了跨域的功能。怎一个棒字了得!
CORS在request中,只用加入Origin的字段,传输所在域名,服务器只用判断这个Origin是否在自己允许的跨域域名之列,返回一个Acces-_系列的HTTP头即可。
OK,我们看一下http://coffeesherk.github.io 中的一个小例子。
image
此图中关于Access-Control-_字段的解释,看看MDN可能更清晰
https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
好吧,稍微说一下

Access-Control-Allow-Credentials

表明这个reponse是否可信,可被显示,它的值是true | false

Access-Control-Expose-Headers

表明response中返回的一些header哪些可以被客户端获取。

Access-Control-Allow-Origin

表明哪些域名可以访问(可以用通配符*)

祝周末愉快~

错排

错排水题
http://acm.hdu.edu.cn/showproblem.php?pid=2048
http://acm.hdu.edu.cn/showproblem.php?pid=2049
http://acm.hdu.edu.cn/showproblem.php?pid=2068

N种所有排列可能自然是Ann = N!种排列方式
现在的问题就是N张票的错排方式有几种。
首先我们考虑,如果前面N-1个人拿的都不是自己的票,即前N-1个人满足错排,现在又来了一个人,他手里拿的是自己的票。
只要他把自己的票与其他N-1个人中的任意一个交换,就可以满足N个人的错排。这时有N-1种方法。
另外,我们考虑,如果前N-1个人不满足错排,而第N个人把自己的票与其中一个人交换后恰好满足错排。
这种情况发生在原先N-1人中,N-2个人满足错排,有且仅有一个人拿的是自己的票,而第N个人恰好与他做了交换,这时候就满足了错排。
因为前N-1个人中,每个人都有机会拿着自己的票。所以有N-1种交换的可能。
综上所述:f(n) = (i - 1) * [f(n - 1) + f(n - 2)]

这里想通为什么n-2要加进去想了我很久。
我在想 当n-1其中有一个不满足错排的时候,把它改成错排不就行了。
事实上是不对的。
怎么想呢,当n-2放一个东西到n-1上时,有f(n-1)是正确的。但是n-1个其中有一个不是错排,再加一个变成n个时,换一下位置就能变成正确的,这一个我没有考虑到

举个例子

1 2 3 4

当 n = 3的时候

2 3 1
3 1 2

这是符合要求的

3 2 1

这个是不符合要求的,但是这个组合 加1个4 换一下,就符合要求了

3 4 1 2

但是这个 组合却不能用n=3的组合 一次交换得到。
而且满足这个组合的条件是n-2 也就是n = 2时必须满足要求。
显然这样的条件存在n-1(3)个。

所以公式是

f(n) = (n-1)*[f(n-1)+f(n-2)]

2013-04-30

其实并不知道这些天有什么内容好写的,Github的Active List会促使人做一些contribution。五一回家虽然说是休息,但依然忙了几天,没有收获,现在应当算是我生活的最低谷了吧,各种事情不顺利。

关于工作

阿温先森:

当你的人生进入最低谷的时候,往前走就是,因为无论什么方向都是向上。

这句话是相当励志,可是谁知道在这个低谷中哪里还有一个坑呢?
我做事总是比别人缺乏一些激情,原因就是因为我看不到我所关心的眼前的利益。得不到以及看不到的原因就是因为平时的懒惰,表现在知难而退,不知道正确学习方法,没有毅力,这些东西,我想说都不用说,你自己应该知道怎么做。现在到不是从始至终的问题,别人都在拼命向上,你却在这边自我感觉良好,这是一个多么大的陷阱,你知道你不想和别人比的原因是什么,就是因为你害怕别人超越你。不要变成弱者!

关于感情

你知道你想得到一些东西就必须抛弃一些东西,哪怕冷血、残酷,造成你内心多么不平衡,你知道有些已经丢弃的东西再也找不回来。你应该想想当初为什么做了这么一个决定。至少你要给自己一个理由不那么憎恨自己。再怎么错乱,你现在的生活是幸福的,你有一个爱你的女朋友,你知道你要做的事情就是好好待她。你自己也知道有时候念念不忘过去,是对过去和现在的不负责任。既然你选择了对那个人的离开,那么就再也不要过问,因为那里的事情早已经是一团糟,早已经理不清楚。感情的事情从来没有谁对谁错,那么,你能做的,就是珍惜现在的幸福。至于以前的回忆,过去了,就过去了,她的幸福现在用不着你操心。

关于生活

你知道生活必须要继续走下去,起码像个男人一样扛起一切。你现在比你爸爸没用多了,你觉得看见未来是很有安全感的事情,那你知道不知道,看见未来是一件很没有挑战性的事情。你知道你讨厌公务员的原因,虚伪,阿谀奉承,没有挑战性,你内心却又渴望那一份安定。但生活是公平的,从前的你,经历了太多的舒适,你终于没有机会再得到它。你知道你想要的是什么,所以,你现在需要反其道而行之,你需要挑战你自己,让你配得上那一份安定。这些话,你需要经常去看一看。

2013-04-25

这几天身体实在太差了。
发烧烧了四天,请了两天的假,薪水扣了不少,心疼。
明天后天又要请假有事,真的很不爽。
这些天没有看书,忙的很,也没有看算法题,但是没有堕落的感觉。万幸。
一直在写前端代码,javascript写得依旧很烂,很难看。但是实现的效果却还是令我满意的。明天希望服务端完成jsonp的东西,让我有数据可以拿。(一个公司的web团队居然没人知道jsonp,这。。也许我说话声音不够响?)
明天可以做个整理了,关于PhoneGap Framework。
还有,关于前端,其实这个我不知道怎么说,大牛实在太多,我是个新手,只是在恰好的时间,有幸可以玩玩html5新特性和CSS3新特性而已。

2013-04-15

这两天又要忙疯了。
碰到一道SPOJ的DP题 又手足无措了,隔了两天没有时间去好好理解。今天在研究CSS3的东西。叔要强迫我们进入Web App的世界了~
看看iOS的历史发展 貌似是从Web App 进入到Native App的,现在又要切换回去嘛?好吧~小的技术不够,背景不深,无法评论这些啦。
不过无论怎么样,HTML5提供的API还是很多,也很容易上手,明天可以做一个waterfall和3D cube的效果出来,应该没什么问题吧。
最近倒腾效果太多,又因为线性代数学的实在不好,脑子都要锈了。
今儿心情愉悦,因为是15号,哈哈。
好了,废话一下,明天继续加油,最近事情真心还有很多,其实习惯忙了也好,以后闲下来就会更有力气,呵呵。
晚安,今天

hi~~

hello~~~~~~~~~~~~~~~~~~~~~~~~~~
can you see me?
you can delete me....

流产的百度音乐widget

所以昨天想做一个百度音乐的播放器。(Mac下没有,老是不小心关了浏览器好烦躁)
所以昨天又碰见了跨域问题。
所以。
所以Dashcode写出的widget貌似是在safari运行时里的。
所以。
就没有然后了。
好想吐槽 T T 求开个API接口也好!

Sencha Touch 使用小记。

这些天为找一个比较好用的mobile framework。费劲心思。

看了jQuery Mobile 、 KISSY Mobile、 Sencha Touch。考虑口碑和文档双重的标准下,我去试用了Sencha Touch。其实EXTjs 我从大二开始就去研究了。但是那会基础不行,对代码敏感度不够,导致学习压力特别大。Sencha Touch改变了以往写网页的思维。也让我对Framework 这个词的想法改变了很多。

最首先的就是,它是一个沉重的框架。用它的后果就是给你带来将近600K的js代码(当然,这个看你对于代码存储的需求,我们是准备把代码放到本地的。)以及一些其他不可控的因素。

就好像用它的概念创造出来的ListView 如若没有Google制造Android这样的决心,它是无法让它的API更加生动可靠的。不过因为HTML5还处于不是特别成熟的阶段,有这样的框架实现还算感到欣慰。
废话说了一大坨,其实我只想记个笔记而已。

Sencha Touch 对于List这块在它的教程里有说明,可以使用SimpleListItem或者ListItem进行布局。

Sencha Touch里面的Compoment有一个属性是造成了我很大困扰的属性,那就是 baseCls 我一直以为和cls一样。 baseCls 指定它的Theme。如果更改了 baseCls ,那么 Sencha Touch 对于该元素默认的样式支持就消失了,而且,我在自定义listitem中更改了 baseCls 的话。。连 itemtap 事件都不能捕获了。这是绝对要引起注意的,也就是说,在更改css类的时候,最好使用它的 cls 属性。

关于坑爹的目录(spm)

用过spm的童鞋都知道。spm的package.json定义如下

{
     "family": "family",
     "name": "name",
     ...
}

这次给自己的首页引入seajs的过程中,查看了各种log,没有特别仔细看,最后发现路径中的family写错了,导致模块一直加载错误,郁闷死了。也好,顺路看了下seajs的源码,发现并不是特别难。

seajs加载包的流程是这样,先提取依赖,然后将各个模块缓存起来,再在模块真正执行的时候,调用到require的地方,进行依赖模块的执行,返回exports给相应的模块。一开始以为require不是函数,今天才发现想错了,require是真正的函数,只不过require里面的参数在之前需要进行解析,因此它还是只能接受字符串参量。

seajs中,模块的加载是提前加载好的,模块的执行是到require的时候才执行。这点也许是我看文档没有明白,和之前的理解不一样。现在算是搞清楚了。

收获还是有的。

最近太背了,希望转运,感谢老天爷让我突然开窍。http://coffeesherk.github.io 已经引入seajs。加上之前的jquery 的CMD化。很OK。

明天继续搞sencha touch。

有没有人推荐一个好一点的类jquery的Application Framework for Mobile。这样我就不需要使用sencha touch了。感觉限定实在太多。一个listitem就快让我疯了。

午休聊天。

今天和一群同事午休的时候聊天。
晚上,安慰女朋友。
几乎都能扯上一个问题——以后做什么,我们该怎么活下去。
其实这两个问题我一个都回答不上来。未来怎么样我们谁又知道。我不相信命,我期待我能牢牢把握运。我们现在无限努力,我相信总能得到我想要的。而且是以我们最自豪的方式。
我明白我缺在哪里。我觉得我比以前好许多了。
也许这样已经比以前好太多了,这是一件值得欣慰的事。
那么谈恋爱也一样吧。我知道我需要什么,我知道我需要付出什么。我都愿意。
生活和你。我都爱。
不浮躁。做好自己。

来玩玩字符串吧(中缀exp和后缀exp互转)

来玩玩字符串吧

其实我想说,坑爹的字符串自古以来就是我最最纠结的一个东西。
我自己也不知道为什么,就是处理不好字符串的问题,就像我处理不好概率问题,就像我学不好生物一样,哈哈哈哈,扯远了。
其实人都应该挠自己痒处是吧~~
嗯,看看SPOJ的一道题Complicated Expressions
题目的本意是去除多余的括号。
Allright,er..好吧,其实我一开始想到应当和中缀表达式后缀表达式什么的有关,这个到是蒙对了。
看到一个帖子,资料,我零零碎碎看了两个星期
http://blog.csdn.net/ace1985/article/details/5609468
要求就是先把中缀表达式转成后缀表达式,再把后缀表达式转回中缀表达式,应当是这样的。

在中缀表达式转成后缀表达式的过程中, 最最重要的一点就是, 操作符栈中,优先级越高的应当排在越上面,也就是说,当优先级高的符号进栈的时候,应该把优先级低的符号出栈,直到优先级高或者相同的符号变成栈顶元素后,再把当前操作符入栈

这个应当是中缀转后缀的心得了。

后缀转中缀的话,碰见操作符,应当提取两次栈顶元素,然后将计算好的子表达式入栈。
子表达式的组成是个递归的过程,应当如下:
子表达式 = 孙表达式1 操作符op 孙表达式2。
至于孙表达式是否含有括号应当视操作符为定,如果操作符op为-或者/,那么孙表达式2应当有括号。

见代码

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <cstring>

std::string str;
char out[251];     //存储操作数和运算结果的堆栈

int pout;       //指向out堆栈的栈顶指针

//中缀表达式转换为后缀表达式,并存于结果字符串out中
void infix2suffix(std::string s)
{
    char tmp[251];//临时堆栈,用于存放操作符(不含操作数)
    int ptmp = 0; //临时堆栈的栈顶指针

    for(int i=0; i<s.length(); i++)
    {
        switch(s[i])
        {
        case '(':   //是开括号,直接进栈
            tmp[ptmp++] = s[i];
            break;
        case '+': //'+'和'-'优先级最低,在遇到开括号之前,循环执行
        case '-':   //弹出堆栈tmp中刚才压入的字符(因为优先级低的在栈底,高的在栈顶)
            while(ptmp && tmp[ptmp-1] != '(' )
            {
                out[pout++] = tmp[--ptmp];
            }
            tmp[ptmp++] = s[i]; //最后把这个字符压入堆栈tmp
            break;
        case '*':  //'*'和'/'不是最低优先级,在遇到开括号'('、优先级较低的'+'和'-'
        case '/':  //之前,循环执行弹出堆栈tmp刚才压入的字符
            //while(ptmp!=0 && tmp[ptmp-1]!='(' && tmp[ptmp-1]!= '+' && //tmp[ptmp-1]!= '-')与下面while等效
            while(ptmp && (tmp[ptmp-1]== '*' || tmp[ptmp-1] == '/'))
            {
                out[pout++] = tmp[--ptmp];
            }
            tmp[ptmp++] = s[i]; //最后把这个字符压入堆栈tmp
            break;
        case ')': //是闭括号,则在遇到开括号'('之前,循环执行弹出堆栈tmp中的字符
            //并把它们添加到结果字符串堆栈out中
            while(ptmp && tmp[--ptmp]!='(' )
            {
                out[pout++] = tmp[ptmp];   
            }
            break;
        default: //是操作数(注意,本题输入不含空格,否则需另外处理)
            //直接将它添加到结果字符串堆栈中
            out[pout++] = s[i];
            break;
        }
    }
    //上面循环完,说明到达了输入字符串的尾部了,此时
    //循环弹出tmp中剩余的字符并添加到结果字符串堆栈out中
    while(ptmp)
    {
        out[pout++] = tmp[--ptmp];
    }
    out[pout] = '\0'; //设置字符串结束标识
}

//后缀表达式转换为中缀表达式out
void suffix2infix(char *s)
{
    char stack[251][251];
    int priority[251];
    int pstack = 0;

    int len = strlen(s); 

    char s1[251];
    char s2[251];

    int k;
    bool c;
    int templen;

    for(int i=0; i<len; i++)
    {
        switch(s[i])
        {
        case '+': //操作符(前两次循环时s[0]和s[1]肯定都是操作数,因为是后缀表达式嘛)
        case '-':   //而且都是双目操作符,因此前¡两次switch执行的是default的代码
        case '*':
        case '/':
            if(s[i] == '*' || s[i] == '/')
                k = 2;   //优先级高
            else
                k = 1;    //优先级低

            if(s[i] == '/' || s[i] == '-')
                c = true;       //可能要添加圆括号
            else
                c = false;  //不需要添加圆括号

            //弹出第一个栈顶元素 这个是孙表达式2 要处理是否有括号的问题
            if(priority[pstack-1]!=0 &&
                //堆栈stack中栈顶元素不是操作数(即是操作符)
                    (priority[pstack-1]<k || (priority[pstack-1]==k && c)))
                    //栈顶元素是操作符且1)优先级低于当前输入字符
                    //或者2)当优先级相同,且当前输入字符是'/'或'-'时,需要添加圆括号
            {
                s2[0] = '(';
                s2[1] = '\0';//字符串结束标识º
                strcat(s2, stack[pstack-1]);
                strcat(s2, ")");      
            }
            else //不需要添加圆括号
            {
                s2[0] = '\0';
                strcat(s2, stack[pstack-1]);       
            }


            //弹出第二个栈顶元素  这个其实应该是孙表达式1
            --pstack;
            if(priority[pstack-1]!=0 && priority[pstack-1]<k)//栈顶元素下面一个//元素是操作符,且优先级小于当前输入字符时
            {
                s1[0] = '(';
                s1[1] = '\0';
                strcat(s1, stack[pstack-1]);
                strcat(s1, ")");      
            }
            else //不需加圆括号
            {
                s1[0] = '\0';
                strcat(s1, stack[pstack-1]); 
            }

            strcpy(stack[pstack-1], s1); //s1存入堆栈,即变为当前栈顶元素
            templen = strlen(stack[pstack-1]);

            stack[pstack-1][templen] = s[i];//将输入字符拼接到s1之后
            stack[pstack-1][templen+1] = '\0';
            strcat(stack[pstack-1], s2); //将s2拼接到s1+s[i]之后
            priority[pstack-1] = k;      //设置输入元素s[i]优先级
            break;
        default: //操作数
            stack[pstack][0] = s[i];
            stack[pstack][1] = 0x0;
            priority[pstack] = 0; //操作数的优先级为0
            ++pstack;
            break;  
        }     
    }
    strcpy(out, stack[0]);
}

int main()
{
    int N;
    std::cin>>N;
    for(int i=0; i<N; i++)
    {
        pout = 0;//结果字符串out的栈顶指针
        memset(out, 0, sizeof(out));//结果字符串堆栈情况
        std::cin>>str;

        infix2suffix(str); //先将中缀表达式转为后缀表达式º
        suffix2infix(out); //再将后缀表达式转为中缀表达式(最少圆括号)

        std::cout<<out<<std::endl;
    }

    system("pause");
    return 0;
}

复习下堆排序

http://blog.csdn.net/v_JULY_v/article/details/6198644
因为最近想要A一道题目,在#8 中提到过Floyd的最短路算法,它适用于多源最短路径的计算,但是不适用于其中提到题目的算法,因为其实提到的题目讲的是要求单源最短路径。单源最短路径一个典型的求法就是dijkstra算法,优化的方式,就是在松弛的时候从最小堆中抽取结点加入s集合。

做一段前奏,复习下堆排序。
首先这个堆其实是个完全二叉树。也就是说,结点的排布可以简单地用一个数组完全表示,堆排序说起来其实很简单,如果是最小堆,那么父节点的值是小于子节点的。如果是最大堆那么就是相反。

贴段刚刚写的小demo做注释吧。

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define MAX 101
int heap[MAX] = { 9,8,7,6,5,4,3,2,1,0 };

void simply_heap(int node,int len) { //递归更换堆中的位置
    int l = 2 * node + 1;
    int r = 2 * node + 2;
    int min_node;
    int t;
    if( l < len && heap[node] > heap[l] ) {
        min_node = l;
    } else {
        min_node = node;
    }

    if( r < len && heap[min_node] > heap[r] ) {
        min_node = r;
    }
        //以上工作是查找查找双亲节点和子节点中最小的那一个
    if( min_node != node ) {
        t = heap[node];
        heap[node] = heap[min_node];
        heap[min_node] = t;

        simply_heap(min_node,len);// 如果需要更改位置的话,那么顺便往下递归把子树中的结点也更新掉。
    }
}

void build_heap(int len) {
    for( int i = (len-1) / 2; i>=0 ; i-- ) {
        simply_heap(i,len);
    }
}

int main() {
    build_heap(10);
    for(int i = 0; i < 10; i++ ) {
        printf("%d\n",heap[i]);
    }
    system("pause");
    return 0;
}

堆的实际用例就是优先队列,在dijkstra算法中可以用来优化时间复杂度。
堆排序的信息:
时间复杂度:O(nlgn)...
//等同于归并排序
最坏:O(nlgn)
空间复杂度:O(1).
不稳定。

Linux 伪终端demo

啥都不说,先贴上这段demo,免得丢了。就是创建一个终端执行sh
Gist

#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

#define BUFSIZE 1024

int main()
{
    int ptm,sfd;
    char *slavedevice;
    if((ptm = open("/dev/ptmx", O_RDWR)) == -1)
    {
     perror("posix_openpt() error");
     exit(-1);
    }
    fcntl(ptm, F_SETFD, FD_CLOEXEC);
    if(grantpt(ptm) == -1)
    {
     perror("grantpt() error");
     exit(-1);
    }
    if(unlockpt(ptm) == -1)
    {
     perror("unlockpt() error");
     exit(-1);
    }
    if((slavedevice=ptsname(ptm)) == NULL)
    {
     perror("ptsname() error");
     exit(-1);
    }
    int pid = fork();
    if( pid == 0 ) {

        close(ptm);
        setsid();

        int pts = open(slavedevice, O_RDWR);

        if(pts < 0) exit(-1);
        dup2(pts, 0);
        dup2(pts, 1);
        dup2(pts, 2);

        execv("/bin/sh",NULL);
        exit(0);
    }

    int nread;
    char buf[BUFSIZE];
    if( fork() == 0 ){

        for(;;)
        {
        if( (nread=read(STDIN_FILENO,buf,BUFSIZE)) < 0 ){
                perror("read");
                break;
            }
            else if( nread == 0 )
                break;
            if( write(ptm,buf,nread) != nread ){
                perror("write");
                break;
            }
        }
    } else {
        for(;;)
        {
            if( (nread = read(ptm,buf,BUFSIZE) ) <0 )
                break;
            if( write (STDOUT_FILENO,buf,nread) != nread ){
                perror("write");
                break;
            }
        }
    }
    close(ptm);

    return 0;
}

让我受一些启发的小代码
好了,说下目的。曾经很蛋疼地想在Android上做一个简单的IDE,编译器当然还是用GCC,但是,想使用牛逼一些的控件,实现类似终端模拟器的效果。一开始当然简单地使用流的重定向。因为stdin的缓冲问题,造成了我特别多的困扰,后来经过一些学习,知道了有伪终端这种东西,于是今天就开始学习伪终端,终于功夫不负有心人,做出了一个小demo。
当然, 贴上功劳很大的知识篇 至少让我理解了什么叫主从终端。
好了,最后我实现的功能,就是从主设备写入,并从主设备读出,刚傻乎乎地忘了线程阻塞的问题,后来fork了一个子进程,终于发现,是对的,原理见图,读写都是使用主设备,它会类似像管道一样从从设备中反映出来,由于我使用dup2将从设备的输入输出流全部复制到标准输入输出流,所以就能执行我想要的效果啦,当然还有点小瑕疵,有空再改改

jQuery的CMD化

ADC之前来一发 - 关于jQuery的CMD化

最近使用@lifesingerseajs更加频繁,由于seajs在2.0以后进行了更多的精简化,去掉shim插件后,要想使用jQuery,不了解内部逻辑的情况下,只能使用全局变量了。(好吧,我是偷懒,没有好好找文档,不过哥们,你的文档虽然看起来好看,但是我感觉找起来还是好麻烦。懒人的吐槽。)

所以一直想找jQuery CMD化的方法,在seajs的评论中找到了
https://github.com/cmdjs/jquery/blob/master/jquery/Gruntfile.js
看函数

function repl(code, filename) {
    var id = pkg.family + '/' + pkg.name + '/' + pkg.version + '/' + filename;
    code = code.replace(/&&\s*define\.amd\s*&&\s*define\.amd\.jQuery/, '');
    code = code.replace(/define\(\s*"jquery/, 'define("' + id);
    code = code + '\n;$.noConflict();\n';
    return code;
  }

第二行是没有找到替换了啥东西
第三行是将其对AMD模块的支持转换为对CMD模块的支持(也就是在这里加上了CMD的id(对应于famliy/name/version/filename)
后面使用$.noConflict()取消了全局变量对于$的使用。

好了 ,有了标准化的CMD define函数,CMD化就完成了。
我本来还想人肉尝试。。看来这种方法更轻松点~

Todo

  • Seajs id2Uri

关于webkit css的杂碎

今天做的东西优化了很多,却不知道怎么记录我学到的东西,感觉跟裤腿一样短的文章很不好写。

比如我想说:

-webkit-image-set

这个属性可以用来设置不同pixel-ratio的屏幕(当然,我当初只考虑了1dpp和2dpp,当时设置的时候忘记设置默认,导致了小米1S这种1.5dpp的设备居然啥都不显示,我觉得要设置连续范围的而非离散的条件时,用media query更加合适,因为可以使用 min-device-pixel-ratiomax-device-pixel-ratio 来设置范围

还有记忆深刻的-webkit-backface-visibility (可以优化layout性能么?不过使用立方体的时候 美观了很多到是真的。。。) 其他的暂时搁一边吧~~哈哈哈 没有系统的东西可以说

history pushState

Hi,大家七夕快乐~
妹纸不在身边,真心感觉难过~
好吧,我们就是在异地互相难过着 = =

今天在TODO list中加了 pushState这个任务,
回家后就稍微看了下。它属于history的函数,拥有三个参数,分别为data title和url
data是存储当popState发生的时候,读取存储的数据,title是干嘛用的呢。。。。我也不知道= = url就是更改的url了可以让浏览器完美支持后退和前进

replaceState还没有看明天抽时间去看看,
这两天公司好忙。要发新的版本,只能尽量抽时间啦

Android requestLayout和layout

这几天发生很多事情。
我决定换工作了,因为我觉得闷了,我也不知道为什么。
我也不想知道一些太多你不能讲不能说的原因,那么,决定了就是决定了吧。
这真的和失恋一样难过,太多感性和理性的认知。
好了,说了太多矫情的话,这一次想记录的一点东西是Android的layout问题。

Android在布局到绘制view会经历三个步骤,分别是measure,layout,draw。

  1. measure是用来测量宽度和高度的,是Android中相对布局很重要的一环。
  2. layout就是摆放控件用的,决定了控件的位置和大小。
  3. draw是真正绘制控件用的。

android和iOS布局最大的不同我认为iOS中并没有1、2两步,因为一切都是像素级别操作,对于位置,早就已经决定好了,而且是程序员直接决定的。只需要draw出来就可。Android相对来讲,就麻烦了许多。
那么Android中有个重要的方法是requestLayout,一般用于AddView或者View的LayoutParameter改变,或者类似于TextView setText等行为,只要有可能造成位置或者大小改变的(Animation除外),都会重新进行layout,layout非常耗时,一般它需要去通知整个layout层级树去重新布局,绘制,因此耗费很多的时间。
requestLayout会在消息队列中,传入layout请求(其实是把子控件的私有标志位置为布局无效,然后在进行新的请求的时候,就会重新布局),然后整个View树就重新布局,计算位置,进行2->3的过程。
在最早以前,我们使用下拉刷新的时候,就是这么做的,然后卡到死。
所以在没有明确要求物体位置改变的时候,还是用Animation好,或者在Animation结束的时候,再设置layout。

HTTP中boundary的注意事项

今天做文件上传的时候,被boundary坑了下。我意味着我提交出去的request出现了重大BUG!!
好吧,是这样的。

HTTP使用multipart form-data编码的时候,由于存在二进制数据,所以它会在项目和项目之间 使用一个分隔符来分隔,这个分隔符叫做boundary。boundary是随机生成的,并在HTTP头中指明好,好了,这些都不是坑。坑是这样的,--boundary\r\n 代表了数据的开始boundary,然后接下去是你的ContentType啦或者其他的什么东西,然后是\r\n\r\n加入数据。下一行如果还有内容,就加进去一个--boundary 没有内容了,就使用--boundary-- 忘了后面两个-符号,纠结了两天!

提交的代码 发现重大BUG了。。不知道能不能取消不,已经丢脸啦!
今天挺晚了,先睡了

jQuery Deferred Object 初探

Deferred Object

刚知道这个东西的时候,是在我大四刚开始的那会,学姐在阿里巴巴实习,然后碰到这个对象。
我一开始并不知道是什么玩意,然后去网上查了下资料,了解了下概念,但是具体的API还没来得及学习,最近一直在看jQuery相关的东西,看了DOM选择和操作,接着就开始Deferred Object。
事实上我把它定义为 流程控制对象, 这个名词是不是太*了?
好吧,说它是流程控制,因为它和wind.js一样,是用来控制异步流程的。(这么解释没有错吧?)
看看Deferred Object几个重要的API。

// 创建 Deferred Object
var dtd = $.Deferred(); // API 1
var wait = function(dtd){
 setTimeout(function() {
    // 更改dtd的状态
    dtd.resolve(); //API 2 更改Deferred Object 状态
},5000);
  return dtd;
$.when(dtd)
  .done() // API 3 设置Deferred Object 状态为resovled的回调
  .fail() // API 4 设置Deferred Object 状态为rejected的回调

当然 它可以绑定多个回调,如同

 $.when(dtd).done().done()

在内部,它是用一个list保存回调的。

还有个很重要的API是 promise() 它返回一个Promise对象,里面去除了对Deferred Object 状态改变的函数,如resolve,reject等,防止它的状态被外部改变。其实从源码上看Deferred Object 是由接受resovle、reject函数的对象extends Promise对象而来。

今天先简介那么多吧~ 过些天可以分享下源码。

关于我其二

对技术的不专注,带来的明天是什么?

对于这样的话题很慌张,比喻联想到小时候玩网络游戏,看见一个职业牛逼选一个职业,看见另一个职业比这个职业牛逼就又选了另外一个,最后没有一个角色是牛逼的。这就是真理么?

真的很不愿接受这个现实,我喜欢许许多多不一样的技术,都想尝试一下。梦想中的样子,还真的就是挺可笑的——幻想开个公司,CEO是我,开发是我,产品经理是我。这样就不需要任何人了,成为一个全人。大家都笑着说不可能的,如果是平时的我早就动摇了,为什么只有在这一条上,我能这么坚定不移,我到底是靠着什么东西才这么坚持己见的呢。

我今天被喷了,喷的我很不服气。你的梦想是金钱,我的梦想不仅仅是金钱。为什么我要和你一样?

jQuery Deferred Object resolve API

Deferred Object 状态表

jQuery Deferred Object 有三种状态.

  1. pending.
  2. resolve.
  3. reject

三种状态只能单一转换,对应了三种不同的回调函数,分别为 progress done fail。

回调函数缓存

在回调的缓存中,涉及了jQuery的Callback对象,大概有三种不同的回调链(猜测),正准备去详细看一下。
总之,在Deferred Object生成的时候,会自动注册几个系统用的回调函数,比如改变state的回调,还有disable和lock的回调,具体用处,等我详细去了解一下再说明。

注册和触发

调用done()或者fail()则会把相应的回调函数注册进这个回调函数链,使得resolve或者reject调用的时候,依次触发链中的回调,进行每一步逻辑的处理。

后续我会去学习下jQuery的Callback对象,了解下回调链。

Floyd-Warshall Shortest-Path 算法

Floyd-Warshall算法

多源最短路径(DP)
Floyd-Warshall算法的原理是动态规划。
设为从到的只以集合中的节点为中间节点的最短路径的长度。
若最短路径经过点k,则;
若最短路径不经过点k,则。
因此,。
在实际算法中,为了节约空间,可以直接在原来空间上进行迭代,这样空间可降至二维。(见下面的算法描述)

for k ← 1 to n do
  for i ← 1 to n do
    for j ← 1 to n do
      if ( di,k + dk,j < di,j) then
          di,j = di,k + dk,j;

这里让我最疑惑的一点 就是这里k的for循环和j的for循环是否可以换下位置,当时觉得一点问题也没有
整理下就是

for i ← 1 to n do
  for j ← 1 to n do
    for k ← 1 to n do
      if ( di,k + dk,j < di,j) then
          di,j = di,k + dk,j;

其实差的很多。
k的每一次迭代,都会让整个最短路重新松弛一遍。
会让所有相邻的边都找出最短路径。加入新边。
k的位置不能调换

这点可以自己手动写代码去证实

#include <stdio.h>
#include <string.h>
#include <iostream>
#define N 11
int map[N][N];
int dist[N][N];
const int INF = 100000;
void init (){
    int i,j;
    for(i=0;i<N;i++) {
        for(j = 0; j < N; j++) {
            map[i][j]=(i==j)?0:INF;
        }
    }
    memset(dist,-1,sizeof(dist));
    map[1][8] = 1;
    map[8][9] = 2;
    map[9][2] = 3;
    map[9][3] = 4;

}

void fun() {
    int i,j,k;
    for( i = 1; i < N; i ++) {
        for( j = 1; j < N; j++) {
            dist[i][j] = map[i][j];
        }
    }
    for(k = 1; k < N; k ++){
        for(i = 1;i < N; i++) {
            for(j = 1; j< N; j++) {
                if(dist[i][k]!=INF&&dist[k][j]!=INF&&dist[i][j]>dist[i][k]+dist[k][j]) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                }
            }
        }
    }
    printf("%d\n",dist[1][2]);
}
int main() {
    init();
    fun();
    system("pause");
    return 0;
}

测试代码~

噢对了,贴个练习题吧
到时候可以准备用SPFA重写
The Shortest Path

利用二级指针删除单向链表

本文转载自http://coolshell.cn/articles/8990.html

其实是昨天robin和peter讨论链表知识的时候,突然想到之前看到过这篇文章。
今天想再仔细看看,理解下含义。
在没有指针的环境下待多了,拿到指针就很没有安全感是吧。
这是我们一般人都会写的删除指针的方法

typedef struct node
{
    struct node * next;
    ....
} node;

typedef bool (* remove_fn)(node const * v);

// Remove all nodes from the supplied list for which the
// supplied remove function returns true.
// Returns the new head of the list.
node * remove_if(node * head, remove_fn rm)
{
    for (node * prev = NULL, * curr = head; curr != NULL; )
    {
        node * const next = curr->next;
        if (rm(curr))
        {
            if (prev)
                prev->next = next;
            else
                head = next;
            free(curr);
        }
        else
            prev = curr;
        curr = next;
    }
    return head;
}

来一种Linus所说的low-level-coding的二级指针删除办法(脑子需要稍微仔细想一下)
最重要的一点就是 指针本身也是一个变量,指针变量具有自己的地址。
int *a; 这个a就在栈上拥有一个地址。那么

int **b = &a; 
int c;
*b =&c;

就能操纵这个a变量。
来看下面一个删除指针的代码

void remove_if(node ** head, remove_fn rm)
{
    for (node** curr = head; *curr; )
    {
        node * entry = *curr;
        if (rm(entry))
        {
           *curr = entry->next;
            free(entry);
        }
        else
            curr = &entry->next;
    }
}

特别是中间一段
这里要注意的是,要摒弃 prev->next = curr->next;
这种惯性思维。

哇!Ant

哇 Ant

第一次使用Ant是很久很久以前,做1034那会吧~
后来在mintcode做OA的时候,部署PHP用了一次
今天在使用Android部署的时候,又用了一次。
稍微熟了点 因为我对批处理不熟练T T
嗯 引用下文章
熟悉下渠道化打包的时候 用Ant循环生成。

好棒!

背包再解析

嗯,多年来再来看一次背包。
记得应该是大二寒假,在艰苦的环境下(所有人都要出去玩,努力一个人沉下来学习,噢,这个感觉真的太痛苦了!!),写出了第一个背包题。
虽然现在为自己的幼稚成长感到很可笑。但是,毕竟也是成长必经之路了。
D大的背包九讲写的真心很nice。
我看到这个东西的时候,第一想到的不是去写写背包的sample,而是直接点了查看源代码,因为页面看着太舒服了。开个玩笑。

基础背包问题(01背包)
其实是很简单的一段代码
f[v][i]代表背包容量是v的时候,放入i物品所具有的最优价值。
v 就是容量
i 就是物品i
c[i] 代表物品i所占用的体积
w[i] 代表物品i的价值
一件物品只能放一次

for i=1..N
    for v=V..0
        f[v]=max{f[v],f[v-c[i]]+w[i]};

这就是解了。。。。

好,先不解释,到完全背包问题上来
一件物品可以放很多次

for i=1..N
    for v=0..V
        f[v]=max{f[v],f[v-c[i]]+w[i]}

这里的差别只有v的顺序从v...0 到0...v。
这里的差别文字实在很不好描述。
好吧这是我个人问题
不过可以细细想一下,v从c[i]增加到V 如果V是c[i]的两倍之多,c[i]就是可以添加多次的。

但01背包问题中,小容量是后算的,但是计算大容量需要用到小容量的结果,在小容量还没有计算进c[i]的值时,c[i]是不存在在背包中的,所以只可能存在一次
举个栗子

c = 2
V = 7;
f[7] = max{f[7],f[5]+w[i]};

但是f[5]却还没有参与c的计算,到计算f[5]的时候,又已经和f[7]无关了。
所以这里的巧妙之处就在于这个遍历V的顺序

今天有空详细研究下多重背包 喜欢的人先去看看呗

PhoneGap & HTML5 & CSS3

应叔的要求,开始研究这块内容。
乔布斯曾经说过,许多事情,到最后都会串起来。
我曾以为我的学习漫无目的,也许是好的。
我的前端知识和移动开发就在这一个时候串了起来。
不能说得心应手,起码入门还算顺利,我就是这么不争气的哈哈哈哈。

一上来在Corvoda框架下,用了@lifesinger 的seajs。作为一个非专业前端开发,之前就很欣赏seajs,只不过一直没有用武之地,今儿总算可以拿起了来用了。js的模块开发、函数式编程我还是很不适应,多看看犀牛书也许能解决。js的优势就在于OpenSource的东西特别多,有许多值得学习,比如在大学里就开始要看的Secha 只不过API到现在我还不是很清楚,哈哈。因为提供一套成型的UI框架我觉得改起来还是很难入手,知难而退的潜意识在作怪啊。不过要知道,我可不像以前那样容易被打败。

作为母语是中文的人,看见两个单词想死的心都有。transition和transform,虽然一个是描述变换,一个是描述变形的。这里做一个自己的解释。。transition描述动画的改变过程,而transform是坐标变换啊!!!

今天发现CSS还可以做关键帧动画,就是keyframe啦~ 也许是一个大发现。然后在transform的过程中貌似fill-animation是没有用的,所以我在touchmove事件里进行transform都是从起点开始到目标点(如果有transtion的话, 没有transition就没有渐变过程啦! ),touchmove是个大坑,希望以后W3C能改改好。Android中dispatchTouch机制(onInterceptTouch)做的就挺不错,可能是习惯了这一套机制。

不管在哪个领域都要加油,努力些!

AC自动机模板

只是贴个模板,
AC自动机就是Trie树和KMP的结合。
http://www.cppblog.com/mythit/archive/2013/05/02/80633.html
这是学习文章

#include <iostream> 
using namespace std; 

const int kind = 26; 
struct node{  
 node *fail;       //失败指针
 node *next[kind]; //Tire每个节点的26个子节点(最多26个字母)
 int count;        //是否为该单词的最后一个节点
 node(){           //构造函数初始化
     fail=NULL; 
     count=0; 
     memset(next,NULL,sizeof(next)); 
 } 
}*q[500001];          //队列,方便用于bfs构造失败指针
char keyword[51];     //输入的单词
char str[1000001];    //模式串
int head,tail;        //队列的头尾指针

void insert(char *str,node *root){ 
 node *p=root; 
 int i=0,index;  
 while(str[i]){ 
     index=str[i]-'a'; 
     if(p->next[index]==NULL) p->next[index]=new node();  
     p=p->next[index];
     i++;
 } 
 p->count++; 
} 
void build_ac_automation(node *root){
 int i;
 root->fail=NULL; 
 q[head++]=root; 
 while(head!=tail){ 
     node *temp=q[tail++]; 
     node *p=NULL; 
     for(i=0;i<26;i++){ 
         if(temp->next[i]!=NULL){ 
             if(temp==root) temp->next[i]->fail=root;                 
             else{ 
                 p=temp->fail; 
                 while(p!=NULL){  
                     if(p->next[i]!=NULL){ 
                         temp->next[i]->fail=p->next[i]; 
                         break; 
                     } 
                     p=p->fail; 
                 } 
                 if(p==NULL) temp->next[i]->fail=root; 
             } 
             q[head++]=temp->next[i];  
         } 
     }   
 } 
} 
int query(node *root){ 
 int i=0,cnt=0,index,len=strlen(str); 
 node *p=root;  
 while(str[i]){  
     index=str[i]-'a';  
     while(p->next[index]==NULL && p!=root) p=p->fail; 
     p=p->next[index]; 
     p=(p==NULL)?root:p; 
     node *temp=p; 
     while(temp!=root && temp->count!=-1){ 
         cnt+=temp->count; 
         temp->count=-1; 
         temp=temp->fail; 
     } 
     i++;                 
 }    
 return cnt; 
} 
int main(){ 
 int n,t; 
 scanf("%d",&t); 
 while(t--){  
     head=tail=0; 
     node *root=new node(); 
     scanf("%d",&n); 
     getchar(); 
     while(n--){ 
         gets(keyword); 
         insert(keyword,root); 
     } 
     build_ac_automation(root); 
     scanf("%s",str); 
     printf("%d\n",query(root));  
 } 
 return 0; 
}

2013-04-19

今天在做页面的时候,碰到好些问题。
我一开始还不知道同为webkit的safari和chrome竟然表现这么不一致。
更痛苦的是Samsung Galaxy Note scroll事件居然不传达touchend。导致竖滑后就不能横向滑动了,还不知道什么解决办法。
留几个问题吧:

  • transformZ后遮住前面的控件(chrome)
  • safari挡住一部分
  • safari的scroll和document的scroll冲突,到时候再解决看吧。。。。

javascript 中原型和constructor的返回值的一些tips

原型的一些小知识

在原型编程中,或者说面向对象编程中,我们总会写出以下代码

 var obj = new MyObject(); 

我们一般写这个构造函数的时候,都是这么写的

var MyObject = function() {
            // something you want to do
};

如果要对这个类进行扩展的话,就会去扩展它的原型对象 prototype
类似代码如下

MyObject.prototype = {
     'foo':'bar'
}

根据《javascript权威指南》我们可以知道,判断一个对象是不是一个“类”的实例,
一般采用 instanceof 关键字。在我们传统的面向对象编程中,MyObject 绝对是obj的类。在js中与之对应的是constructor,但是在js中,和传统OO有很大区别的是,MyObject不一定是obj的“类”,它只是obj的构造函数而已,在原型模式中,构造函数不同不意味着对象所属的类不同,但是 如果两个object所拥有的prototype对象不同的话,那么他们就不属于一个类
用代码来说 就是说
如果
a.prototype !== b.prototype
那么他们的类就是不相同的,这个条件起决定的作用,跟他们的constructor是否相同无关。
这是一个非常有趣的现象。

关于Constructor的返回值

今天看jQuery Source的时候会看见很多Constructor都有一个返回值,当然在此之前,我从来不会在Constructor中添加返回值,因为它默认返回this。后来查阅相关资料。Constructor如果具有返回值的话,要判断下返回值的类型,如果返回值的类型是一个object,那么产生的对象的prototype和object相同,如果不是个object的话,就返回this。
show code:

var MyObject = function(o) {
     if( o == 2 ) {
        return { }
     } else if ( o == 1 ) {
       return 1 
     } 
}

可以在Chrome的Console中看下他们的类型,会很有趣哦~

Android 图像 Matrix 前乘后乘表象作用

图像Matrix

对我来说 线性代数已经忘光光啦,最近的项目中要用到图像变换,产生一个Cube的样子。找了一天的源码,总算找全了。
线性代数的知识忘光啦。

不过做点小总结吧,图像矩阵应该是如下的模样

[ cosΦ sinΦ 0 ]
[ sinΦ -cosΦ 0 ]
[ 0       0   1]

做一次以中心点的变换,一般是先做变换,再进行矩阵相对于作用点的后乘+前乘。
比如说要做距中心的旋转,那么简单的方法就是
先rotate再transition。
但是有一点还不明白。

绕中心点旋转 再右移N个像素,这样的矩阵变化是怎么样的?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.