分类归档: Programming

NGINX userid 分析、解码

生成userid的代码在 http/modules/ngx_http_userid_filter_module.c 大概550行左右。
uid_set 是4个uint32构成的,其中比较有用的是第二个unit32,是userid的生成时间。第四个是一个递增值 以 0x03030302 为初始值,每次递增0x100。

default: /* AF_INET */
                sin = (struct sockaddr_in *) c->local_sockaddr;
                ctx->uid_set[0] = sin->sin_addr.s_addr;
                break;
            }

        } else {
            ctx->uid_set[0] = htonl(conf->service);
        }

        ctx->uid_set[1] = htonl((uint32_t) ngx_time());
        ctx->uid_set[2] = htonl(start_value);
        ctx->uid_set[3] = htonl(sequencer_v2);
        sequencer_v2 += 0x100;
        if (sequencer_v2 < 0x03030302) {
            sequencer_v2 = 0x03030302;
        }
// 用PHP解码nginx userid
$str = $_REQUEST["uid"] ?: $_COOKIE['uid'];

function nginx_userid_decode($str)
{
        return  unpack('N*', base64_decode(str_replace(' ', '+', $str)));
}

$hash = nginx_userid_decode($str);
var_dump($hash);
date_default_timezone_set("UTC");
var_dump(date("Y-m-d H:i:s", $hash[2]));

参考文章:
http://www.lsproc.com/blog/nginx_userid_decode/

SimpleScriptLoader for Firefox 一个简单的脚本加载工具

最近在做的一个项目需要调用JS文件对网页内容进行修改,老是用Firefox复制粘贴特别麻烦,于是乎就顺手写了个小扩展SimpleScriptLoader。这个小东西可以手动或者自动的加载指定的JS文件,非常简单易用。

支持在任何网页打开时加载指定的脚本文件,还可以设置自动加载,在选项面板中能设置允许自动加载的URL地址。

开源协议:GPL v3

代码托管在GitHub:https://github.com/HessianZ/simple-script-loader

0.1版已经发布到了Firefox扩展中心:https://addons.mozilla.org/zh-CN/firefox/addon/simple-script-loader/

界面截图

选项面板截图

广告术语 CPM、CPC、CPA 是什么意思?

1.CPM(Cost Per Mille,或者Cost Per Thousand;Cost Per Impressions) 每千人成本
 
  网上广告收费最科学的办法是按照有多少人看到你的广告来收费。按访问人次收费已经成为网络广告的惯例。CPM(千人成本)指的是广告投放过程中,听到或者看到某广告的每一人平均分担到多少广告成本。传统媒介多采用这种计价方式。在网上广告,CPM取决于“印象”尺度,通常理解为一个人的眼睛在一段固定的时间内注视一个广告的次数。比如说一个广告 横幅的单价是1元/CPM的话,意味着每一千个人次看到这个Ban-ner的话就收1元,如此类推 ,10,000人次访问的主页就是10元。?
 
  至于每CPM的收费究竟是多少,要根据以主页的热门程度(即浏览人数)划分价格等级,采 取固定费率。国际惯例是每CPM收费从5美元至200美元不等。
 
2.CPC(Cost Per Click;Cost Per Thousand Click-Through) 每点击成本
 
  以每点击一次计费。这样的方法加上点击率限制可以〖WX)〗加强作弊的难度,而且是宣传网站站点的最优方式。但是,此类方法就有不少经营广告的网站觉得不公平,比如,虽然浏览者没有点击,但是他已经看到了广告,对于这些看到广告却没有点击的流量来说,网站成 了白忙活。有很多网站不愿意做这样的广告,据说,是因为传统媒体从来都没有这样干过。
 
3.CPA(Cost Per Action) 每行动成本?
 
  CPA计价方式是指按广告投放实际效果,即按回应的有效问卷或定单来计费,而不限广告投 放量。CPA的计价方式对于网站而言有一定的风险,但若广告投放成功,其收益也比CPM的计 价方式要大得多。 ? 广告主为规避广告费用风险,只有当网络用户点击旗帜广告,链接广告主网页后,才按点击 次数付给广告站点费用。

一些网站开发中常用到的Javascript项目

图片轮播 SlideJS

SlidesJS is a responsive slideshow plug-in for jQuery (1.7.1+) with features like touch and CSS3 transitions. Give it a try above and check out the examples to help you get started adding SlidesJS to your project.

官方地址: http://www.slidesjs.com/

 

图片滚动(Marquee) jCarousel

jCarousel是一款 jQuery 插件, 用来控制水平或垂直排列的列表项. 这些项目(可以是静态HTML内容或是Ajax加载内容)内容是可以来回滚动的(可以有动画效果)。

官方地址: http://sorgalla.com/jcarousel/

中文文档:http://www.zhangxinxu.com/jq/jcarousel_zh/

 

图像放大 Etalage

A ready to use jQuery image zooming plugin to present your images in the highest detail without leaving the page.

官方地址:http://frique.me/etalage/

 

简单粗暴的在线编辑器 KindEditor

KindEditor 是一套开源的在线HTML编辑器,主要用于让用户在网站上获得所见即所得编辑效果,开发人员可以用 KindEditor 把传统的多行文本输入框(textarea)替换为可视化的富文本输入框。

官方地址:http://www.kindsoft.net

 

树状列表 zTree

zTree 是一个依靠 jQuery 实现的多功能 “树插件”。优异的性能、灵活的配置、多种功能的组合是 zTree 最大优点。

官方地址:http://www.ztree.me/v3/main.php

 

数据报表 Google Chart

Google chart tools are powerful, simple to use, and free. Try out our rich gallery of interactive charts and data tools.

官方地址:https://developers.google.com/chart/?hl=zh-CN

[转]Android技术积累:图片缓存管理

转自:http://keegan-lee.diandian.com/post/2012-12-06/40047548955

 

如果每次加载同一张图片都要从网络获取,那代价实在太大了。所以同一张图片只要从网络获取一次就够了,然后在本地缓存起来,之后加载同一张图片时就从缓存中加载就可以了。从内存缓存读取图片是最快的,但是因为内存容量有限,所以最好再加上文件缓存。文件缓存空间也不是无限大的,容量越大读取效率越低,因此可以设置一个限定大小比如10M,或者限定保存时间比如一天。

因此,加载图片的流程应该是:

1、先从内存缓存中获取,取到则返回,取不到则进行下一步;

2、从文件缓存中获取,取到则返回并更新到内存缓存,取不到则进行下一步;

3、从网络下载图片,并更新到内存缓存和文件缓存。

 

接下来看内存缓存类:ImageMemoryCache

public class ImageMemoryCache {
    /**
     * 从内存读取数据速度是最快的,为了更大限度使用内存,这里使用了两层缓存。
     * 硬引用缓存不会轻易被回收,用来保存常用数据,不常用的转入软引用缓存。
     */
    private static final int SOFT_CACHE_SIZE = 15;  //软引用缓存容量
    private static LruCache<String, Bitmap> mLruCache;  //硬引用缓存
    private static LinkedHashMap<String, SoftReference> mSoftCache;  //软引用缓存

    public ImageMemoryCache(Context context) {
        int memClass = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
        int cacheSize = 1024 * 1024 * memClass / 4;  //硬引用缓存容量,为系统可用内存的1/4
        mLruCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                if (value != null)
                    return value.getRowBytes() * value.getHeight();
                else
                    return 0;
            }

            @Override
            protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
                if (oldValue != null)
                    // 硬引用缓存容量满的时候,会根据LRU算法把最近没有被使用的图片转入此软引用缓存
                    mSoftCache.put(key, new SoftReference(oldValue));
            }
        };
        mSoftCache = new LinkedHashMap<String, SoftReference>(SOFT_CACHE_SIZE, 0.75f, true) {
            private static final long serialVersionUID = 6040103833179403725L;
            @Override
            protected boolean removeEldestEntry(Entry<String, SoftReference> eldest) {
                if (size() > SOFT_CACHE_SIZE){    
                    return true;  
                }  
                return false; 
            }
        };
    }

    /**
     * 从缓存中获取图片
     */
    public Bitmap getBitmapFromCache(String url) {
        Bitmap bitmap;
        //先从硬引用缓存中获取
        synchronized (mLruCache) {
            bitmap = mLruCache.get(url);
            if (bitmap != null) {
                //如果找到的话,把元素移到LinkedHashMap的最前面,从而保证在LRU算法中是最后被删除
                mLruCache.remove(url);
                mLruCache.put(url, bitmap);
                return bitmap;
            }
        }
        //如果硬引用缓存中找不到,到软引用缓存中找
        synchronized (mSoftCache) { 
            SoftReference bitmapReference = mSoftCache.get(url);
            if (bitmapReference != null) {
                bitmap = bitmapReference.get();
                if (bitmap != null) {
                    //将图片移回硬缓存
                    mLruCache.put(url, bitmap);
                    mSoftCache.remove(url);
                    return bitmap;
                } else {
                    mSoftCache.remove(url);
                }
            }
        }
        return null;
    } 

    /**
     * 添加图片到缓存
     */
    public void addBitmapToCache(String url, Bitmap bitmap) {
        if (bitmap != null) {
            synchronized (mLruCache) {
                mLruCache.put(url, bitmap);
            }
        }
    }

    public void clearCache() {
        mSoftCache.clear();
    }
}

文件缓存类:ImageFileCache

public class ImageFileCache {
    private static final String CACHDIR = "ImgCach";
    private static final String WHOLESALE_CONV = ".cach";

    private static final int MB = 1024*1024;
    private static final int CACHE_SIZE = 10;
    private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10;

    public ImageFileCache() {
        //清理文件缓存
        removeCache(getDirectory());
    }

    /** 从缓存中获取图片 **/
    public Bitmap getImage(final String url) {    
        final String path = getDirectory() + "/" + convertUrlToFileName(url);
        File file = new File(path);
        if (file.exists()) {
            Bitmap bmp = BitmapFactory.decodeFile(path);
            if (bmp == null) {
                file.delete();
            } else {
                updateFileTime(path);
                return bmp;
            }
        }
        return null;
    }

    /** 将图片存入文件缓存 **/
    public void saveBitmap(Bitmap bm, String url) {
        if (bm == null) {
            return;
        }
        //判断sdcard上的空间
        if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
            //SD空间不足
            return;
        }
        String filename = convertUrlToFileName(url);
        String dir = getDirectory();
        File dirFile = new File(dir);
        if (!dirFile.exists())
            dirFile.mkdirs();
        File file = new File(dir +"/" + filename);
        try {
            file.createNewFile();
            OutputStream outStream = new FileOutputStream(file);
            bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
            outStream.flush();
            outStream.close();
        } catch (FileNotFoundException e) {
            Log.w("ImageFileCache", "FileNotFoundException");
        } catch (IOException e) {
            Log.w("ImageFileCache", "IOException");
        }
    } 

    /**
     * 计算存储目录下的文件大小,
     * 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定
     * 那么删除40%最近没有被使用的文件
     */
    private boolean removeCache(String dirPath) {
        File dir = new File(dirPath);
        File[] files = dir.listFiles();
        if (files == null) {
            return true;
        }
        if (!android.os.Environment.getExternalStorageState().equals(
                android.os.Environment.MEDIA_MOUNTED)) {
            return false;
        }

        int dirSize = 0;
        for (int i = 0; i < files.length; i++) {             if (files[i].getName().contains(WHOLESALE_CONV)) {                 dirSize += files[i].length();             }         }                                                                      if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
            int removeFactor = (int) ((0.4 * files.length) + 1);
            Arrays.sort(files, new FileLastModifSort());
            for (int i = 0; i < removeFactor; i++) {
                if (files[i].getName().contains(WHOLESALE_CONV)) {
                    files[i].delete();
                }
            }
        }

        if (freeSpaceOnSd() <= CACHE_SIZE) {
            return false;
        }

        return true;
    }

    /** 修改文件的最后修改时间 **/
    public void updateFileTime(String path) {
        File file = new File(path);
        long newModifiedTime = System.currentTimeMillis();
        file.setLastModified(newModifiedTime);
    }

    /** 计算sdcard上的剩余空间 **/
    private int freeSpaceOnSd() {
        StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
        double sdFreeMB = ((double)stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;
        return (int) sdFreeMB;
    } 

    /** 将url转成文件名 **/
    private String convertUrlToFileName(String url) {
        String[] strs = url.split("/");
        return strs[strs.length - 1] + WHOLESALE_CONV;
    }

    /** 获得缓存目录 **/
    private String getDirectory() {
        String dir = getSDPath() + "/" + CACHDIR;
        return dir;
    }

    /** 取SD卡路径 **/
    private String getSDPath() {
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState().equals(
                android.os.Environment.MEDIA_MOUNTED);  //判断sd卡是否存在
        if (sdCardExist) {
            sdDir = Environment.getExternalStorageDirectory();  //获取根目录
        }
        if (sdDir != null) {
            return sdDir.toString();
        } else {
            return "";
        }
    } 

    /**
     * 根据文件的最后修改时间进行排序
     */
    private class FileLastModifSort implements Comparator {
        public int compare(File arg0, File arg1) {
            if (arg0.lastModified() > arg1.lastModified()) {
                return 1;
            } else if (arg0.lastModified() == arg1.lastModified()) {
                return 0;
            } else {
                return -1;
            }
        }
    }

}

从网络获取图片:

public class ImageGetFromHttp {
    private static final String LOG_TAG = "ImageGetFromHttp";

    public static Bitmap downloadBitmap(String url) {
        final HttpClient client = new DefaultHttpClient();
        final HttpGet getRequest = new HttpGet(url);

        try {
            HttpResponse response = client.execute(getRequest);
            final int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.SC_OK) {
                Log.w(LOG_TAG, "Error " + statusCode + " while retrieving bitmap from " + url);
                return null;
            }

            final HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream inputStream = null;
                try {
                    inputStream = entity.getContent();
                    FilterInputStream fit = new FlushedInputStream(inputStream);
                    return BitmapFactory.decodeStream(fit);
                } finally {
                    if (inputStream != null) {
                        inputStream.close();
                        inputStream = null;
                    }
                    entity.consumeContent();
                }
            }
        } catch (IOException e) {
            getRequest.abort();
            Log.w(LOG_TAG, "I/O error while retrieving bitmap from " + url, e);
        } catch (IllegalStateException e) {
            getRequest.abort();
            Log.w(LOG_TAG, "Incorrect URL: " + url);
        } catch (Exception e) {
            getRequest.abort();
            Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e);
        } finally {
            client.getConnectionManager().shutdown();
        }
        return null;
    }

    /*
     * An InputStream that skips the exact number of bytes provided, unless it reaches EOF.
     */
    static class FlushedInputStream extends FilterInputStream {
        public FlushedInputStream(InputStream inputStream) {
            super(inputStream);
        }

        @Override
        public long skip(long n) throws IOException {
            long totalBytesSkipped = 0L;
            while (totalBytesSkipped < n) {
                long bytesSkipped = in.skip(n - totalBytesSkipped);
                if (bytesSkipped == 0L) {
                    int b = read();
                    if (b < 0) {
                        break;  // we reached EOF
                    } else {
                        bytesSkipped = 1; // we read one byte
                    }
                }
                totalBytesSkipped += bytesSkipped;
            }
            return totalBytesSkipped;
        }
    }
}

最后,获取一张图片的流程就如下代码所示:

/*** 获得一张图片,从三个地方获取,首先是内存缓存,然后是文件缓存,最后从网络获取 ***/
public Bitmap getBitmap(String url) {
    // 从内存缓存中获取图片
    Bitmap result = memoryCache.getBitmapFromCache(url);
    if (result == null) {
        // 文件缓存中获取
        result = fileCache.getImage(url);
        if (result == null) {
            // 从网络获取
            result = ImageGetFromHttp.downloadBitmap(url);
            if (result != null) {
                fileCache.saveBitmap(result, url);
                memoryCache.addBitmapToCache(url, result);
            }
        } else {
            // 添加到内存缓存
            memoryCache.addBitmapToCache(url, result);
        }
    }
    return result;
}