xml2json in Node.js or browser

Example

xml

<div>
  <p>1</p>
  <span>2</span>
  <a href="#"></a>
  <a href="#2">3</a>
  <link><![CDATA[http://imc.l.qq.com/click?oid=2610061&cid=1350437&adtype=WL&soid=3B257D4600395704C87D09889300&aver=0&ev=37&refluence=4002&requestl=4002&tagid=&si=3430953226&target=4002&isfloatindex=0&pf=H5&loc=LV_1001_YDLDVi_LD&click_data=dXNlcl9pbmZvPXZCVDJuVHN3SEJXNUZPT2RJem9WQzdvZV9KNDI=&live=0&aid_tpid=2&aid_tpid2=1089&aid_tpid3=10470&aid_dura=2684&aid_vid_drm=0&aid_copyright=89&aid_cover=e7hi6lep1yc51ca&aid_subtype=1024_1048576_4&aid_column=0]]></link>
</div>

json

{
  "div": {
    "p": "1",
    "span": "2",
    "a": [
      "",
      "3"
    ],
    "link": "http://imc.l.qq.com/click?oid=2610061&cid=1350437&adtype=WL&soid=3B257D4600…right=89&aid_cover=e7hi6lep1yc51ca&aid_subtype=1024_1048576_4&aid_column=0"
  }
}

android系统webview touch的兼容性总结

移动开发中经常是需要监听touchstart, touchmove, touchend, touchcancel,但是发现,安卓系统的webview如果在touchstart 或者 touchmove 中阻止默认行为,并不会触发touchend. IOS却没有这个问题。

看看这段代码,判断是android设备,就在touchstart的时候preventDefault;

element.addEventListener("touchstart", function(touchEvent) {
  if( navigator.userAgent.match(/Android/i) ) {
    touchEvent.preventDefault();
  }
}, false );

以为这么简单就解决了,no,你在element区域滑动页面试试,是不是不能滑动(别告诉我你的页面没有滚动条)。不要疑惑,preventDefault造成的。
android为了节省性能,监听滑动事件的时候,需要阻止默认的页面滑动行为。ios这点完胜。

解决办法其实也有,看下面的demo吧

参考

实例DEMO

腾讯视频 HTML5 Player 快捷键一览表

快捷键操作 键盘快捷键
space 暂停、播放
K 暂停、播放
M 静音、取消静音
音量+5
音量-5
快退5秒
快进5秒
J 快退10秒
L 快进10秒
F 进入、退出系统全屏
shift + F 进入或退出浏览器全屏
1-9 跳转到影片长度的百分比位置,例如:按下5,跳转到视频的50%的时间点
shift+↑ 播放速度+
shift+↓ 播放速度-
shift+0 播放速度恢复正常

Mac用Homebrew SSL证书错误

brew install lrzsz

通过https下载的时候提示如下错误:

==> Downloading http://www.ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz
==> Downloading from https://ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz

curl: (60) SSL certificate problem: Invalid certificate chain
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.
Error: Failed to download resource "lrzsz"
Download failed: https://ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz
qqlivedeiMac:~ zoborzhang$ wget
wget: missing URL
Usage: wget [OPTION]... [URL]...

Try `wget --help' for more options.

解决办法

cd /Library/Caches/Homebrew/
wget --no-check-certificate https://ohse.de/uwe/releases/lrzsz-0.12.20.tar.gz
brew upgrade lrzsz

html5 video如何判断直播流结束?

img

m3u8文件简介

m3u8,是HTTP Live Streaming直播的索引文件。m3u8基本上可以认为就是.m3u格式文件.

#EXTM3U                     m3u文件头,必须放在第一行
#EXT-X-MEDIA-SEQUENCE       第一个TS分片的序列号
#EXT-X-TARGETDURATION       每个分片TS的最大的时长
#EXT-X-ALLOW-CACHE          是否允许cache
#EXT-X-ENDLIST              m3u8文件结束符
#EXTINF                     extra info,分片TS的信息,如时长,带宽等

未完待续

html5开发之fiddler配置总结

img
fiddler作为开发利器,我们有必要善待ta。多了解怎么用,有助于提升我们的开发效率,接下来看看fiddler能实现哪些为默认没有开启的功能吧。

编辑fidderscript>> Rules>>Customize Rules...(Ctrl+R)

显示服务器IP地址

加入注释下面的代码

static function Main() {
  var today: Date = new Date();
  FiddlerObject.StatusText = " CustomRules.js was loaded at: " + today;

  UI.lvSessions.AddBoundColumn("Server", 50, "@response.server");
  // 显示服务器IP地址
  FiddlerObject.UI.lvSessions.AddBoundColumn("HostIP", 50, "x-hostIP");
}

设置Response Header

找到函数OnPeekAtResponseHeaders,在里面加入以下代码

if (oSession.HostnameIs("livew.l.qq.com")) {
  oSession.oResponse.headers["Access-Control-Allow-Credentials"] = true;
  oSession.oResponse.headers["Access-Control-Allow-Origin"] = "http://m.v.qq.com";
}

设置域名的颜色

找到函数OnPeekAtResponseHeaders,在里面加入以下代码

if (oSession.HostnameIs("v.qq.com")) {
  oSession["ui-color"] = "Aqua";
}

设置可选择的Response Header

在ua的RulesStringValue下面加上如下代码

// Override Allow-origin
RulesString("Override &Allow-origin",true)
RulesStringValue(1,"v.qq.com","http://v.qq.com")
RulesStringValue(2,"m.v.qq.com","http://m.v.qq.com")
RulesStringValue(3,"news","http://view.inews.qq.com")
RulesStringValue(4,"&Custom...","%CUSTOM%")
public static var sAllowOrigin: String = null;

找到函数OnBeforeResponse,在里面加入如下代码

if(sAllowOrigin ){
  oSession.oResponse ["Access-Control-Allow-Credentials"] = "true" ;
  oSession.oResponse ["Access-Control-Allow-Origin"]  = sAllowOrigin ; 
}

显示请求耗时

public static BindUIColumn("Time Taken") 
function CalcTimingCol(oSession:Session) {
  var sResult = String.Empty;
    if (oSession.Timers.ServerDoneResponse > oSession.Timers.ClientDoneRequest) {
    sResult = (oSession.Timers.ServerBeginResponse - oSession.Timers.ClientBeginRequest).ToString();
  }
  return sResult;
}

public static BindUIColumn("ReginResuestTime", 60)
function BeginRequestTime(oSession:Session){
  if(oSession.Timers!==null) {
    return oSession.Timers.ClientBeginRequest.ToString();
  }
  return String.Empty;
}

最后附上完整版的fiddlerscript

import System;
import System.Windows.Forms;
import Fiddler;

// INTRODUCTION
// This is the FiddlerScript Rules file, which creates some of the menu commands and
// other features of Fiddler. You can edit this file to modify or add new commands.
//
// The original version of this file is named SampleRules.js and it is in the
// \Program Files\Fiddler\ folder. When Fiddler first starts, it creates a copy named
// CustomRules.js inside your \Documents\Fiddler2\Scripts folder. If you make a 
// mistake in editing this file, simply delete the CustomRules.js file and restart
// Fiddler. A fresh copy of the default rules will be created from the original
// sample rules file.

// GLOBALIZATION NOTE:
// Be sure to save this file with UTF-8 Encoding if using any non-ASCII characters
// in strings, etc.

// JScript.NET Reference
// http://fiddler2.com/r/?msdnjsnet
//
// FiddlerScript Reference
// http://fiddler2.com/r/?fiddlerscriptcookbook
//
// FiddlerScript Editor: 
// http://fiddler2.com/fiddlerscript-editor

class Handlers {
  // The following snippet demonstrates a custom-bound column for the Web Sessions list.
  // See http://fiddler2.com/r/?fiddlercolumns for more info
  /*
  public static BindUIColumn("Method", 60)
  function FillMethodColumn(oS: Session): String {
  return oS.RequestMethod;
  }
  */

  // The following snippet demonstrates how to create a custom tab that shows simple text
  /*
  public BindUITab("Flags")
  static function FlagsReport(arrSess: Session[]):String {
  var oSB: System.Text.StringBuilder = new System.Text.StringBuilder();
  for (var i:int = 0; i<arrSess.Length; i++)
  {
  oSB.AppendLine("SESSION FLAGS");
  oSB.AppendFormat("{0}: {1}\n", arrSess[i].id, arrSess[i].fullUrl);
  for(var sFlag in arrSess[i].oFlags)
  {
  oSB.AppendFormat("\t{0}:\t\t{1}\n", sFlag.Key, sFlag.Value);
  }
  }
  return oSB.ToString();
  }
  */

  // You can create a custom menu like so:
  /*
  QuickLinkMenu("&Links") 
  QuickLinkItem("IE GeoLoc TestDrive", "http://ie.microsoft.com/testdrive/HTML5/Geolocation/Default.html")
  QuickLinkItem("FiddlerCore", "http://fiddler2.com/fiddlercore")
  public static function DoLinksMenu(sText: String, sAction: String)
  {
  Utilities.LaunchHyperlink(sAction);
  }
  */

  public static RulesOption("Hide 304s")
  BindPref("fiddlerscript.rules.Hide304s")
  var m_Hide304s: boolean = false;

  // Cause Fiddler to override the Accept-Language header with one of the defined values
  public static RulesOption("Request &Japanese Content")
  var m_Japanese: boolean = false;

  // Automatic Authentication
  public static RulesOption("&Automatically Authenticate")
  BindPref("fiddlerscript.rules.AutoAuth")
  var m_AutoAuth: boolean = false;

  // Cause Fiddler to override the User-Agent header with one of the defined values
  // The page http://browserscope2.org/browse?category=selectors&ua=Mobile%20Safari is a good place to find updated versions of these
  RulesString("&User-Agents", true)
  BindPref("fiddlerscript.ephemeral.UserAgentString")
  RulesStringValue(0, "Netscape &3", "Mozilla/3.0 (Win95; I)")
  RulesStringValue(1, "WinPhone8.1", "Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 520) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537")
  RulesStringValue(2, "&Safari5 (Win7)", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1")
  RulesStringValue(3, "Safari7 (Mac)", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9) AppleWebKit/537.71 (KHTML, like Gecko) Version/7.0 Safari/537.71")
  RulesStringValue(4, "iPad", "Mozilla/5.0 (iPad; CPU OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12F5027d Safari/600.1.4")
  RulesStringValue(5, "iPhone6", "Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12F70 Safari/600.1.4")
  RulesStringValue(6, "IE &6 (XPSP2)", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)")
  RulesStringValue(7, "IE &7 (Vista)", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1)")
  RulesStringValue(8, "IE 8 (Win2k3 x64)", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; WOW64; Trident/4.0)")
  RulesStringValue(9, "IE &8 (Win7)", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)")
  RulesStringValue(10, "IE 9 (Win7)", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)")
  RulesStringValue(11, "IE 10 (Win8)", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)")
  RulesStringValue(12, "IE 11 (Surface2)", "Mozilla/5.0 (Windows NT 6.3; ARM; Trident/7.0; Touch; rv:11.0) like Gecko")
  RulesStringValue(13, "IE 11 (Win8.1)", "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko")
  RulesStringValue(14, "IE Edge (Win10)", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.9600")
  RulesStringValue(15, "&Opera", "Opera/9.80 (Windows NT 6.2; WOW64) Presto/2.12.388 Version/12.17")
  RulesStringValue(16, "&Firefox 3.6", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.7) Gecko/20100625 Firefox/3.6.7")
  RulesStringValue(17, "&Firefox 38", "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0")
  RulesStringValue(18, "&Firefox Phone", "Mozilla/5.0 (Mobile; rv:18.0) Gecko/18.0 Firefox/18.0")
  RulesStringValue(19, "&Firefox (Mac)", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20100101 Firefox/24.0")
  RulesStringValue(20, "Chrome (Win)", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.18 Safari/537.36")
  RulesStringValue(21, "Chrome (Android)", "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 5 Build/LMY48B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.78 Mobile Safari/537.36")
  RulesStringValue(22, "ChromeBook", "Mozilla/5.0 (X11; CrOS x86_64 6680.52.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.74 Safari/537.36")
  RulesStringValue(23, "GoogleBot Crawler", "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)")
  RulesStringValue(24, "Kindle Fire (Silk)", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.0.22.79_10013310) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 Silk-Accelerated=true")
  RulesStringValue(25, "&Custom...", "%CUSTOM%")
  public static
  var sUA: String = null;

  // Override Allow-origin
  RulesString("Override &Allow-origin", true)
  RulesStringValue(1, "v.qq.com", "http://v.qq.com")
  RulesStringValue(2, "m.v.qq.com", "http://m.v.qq.com")
  RulesStringValue(3, "news", "http://view.inews.qq.com")
  RulesStringValue(4, "&Custom...", "%CUSTOM%")
  public static
  var sAllowOrigin: String = null;

  // Cause Fiddler to delay HTTP traffic to simulate typical 56k modem conditions
  public static RulesOption("Simulate &Modem Speeds", "Per&formance")
  var m_SimulateModem: boolean = false;

  // Removes HTTP-caching related headers and specifies "no-cache" on requests and responses
  public static RulesOption("&Disable Caching", "Per&formance")
  var m_DisableCaching: boolean = true;

  public static RulesOption("Cache Always &Fresh", "Per&formance")
  var m_AlwaysFresh: boolean = false;

  // Force a manual reload of the script file.  Resets all
  // RulesOption variables to their defaults.
  public static ToolsAction("Reset Script")

  function DoManualReload() {
    FiddlerObject.ReloadScript();
  }

  public static ContextAction("Decode Selected Sessions")

  function DoRemoveEncoding(oSessions: Session[]) {
    for (var x: int = 0; x < oSessions.Length; x++) {
      oSessions[x].utilDecodeRequest();
      oSessions[x].utilDecodeResponse();
    }
    UI.actUpdateInspector(true, true);
  }

  static
  function OnBoot() {
    // MessageBox.Show("Fiddler has finished booting");
    // System.Diagnostics.Process.Start("iexplore.exe");

    // UI.ActivateRequestInspector("HEADERS");
    // UI.ActivateResponseInspector("HEADERS");
  }

  static
  function OnShutdown() {
    // MessageBox.Show("Fiddler has shutdown");
  }

  static
  function OnAttach() {
    // MessageBox.Show("Fiddler is now the system proxy");
  }

  static
  function OnDetach() {
    // MessageBox.Show("Fiddler is no longer the system proxy");
  }

  static
  function OnBeforeRequest(oSession: Session) {
    // Sample Rule: Color ASPX requests in RED
    // if (oSession.uriContains(".aspx")) { oSession["ui-color"] = "red"; }

    // Sample Rule: Flag POSTs to fiddler2.com in italics
    // if (oSession.HostnameIs("www.fiddler2.com") && oSession.HTTPMethodIs("POST")) {  oSession["ui-italic"] = "yup";  }

    // Sample Rule: Break requests for URLs containing "/sandbox/"
    // if (oSession.uriContains("/sandbox/")) {
    //     oSession.oFlags["x-breakrequest"] = "yup"; // Existence of the x-breakrequest flag creates a breakpoint; the "yup" value is unimportant.
    // }

    if ((null != gs_ReplaceToken) && (oSession.url.indexOf(gs_ReplaceToken) > -1)) { // Case sensitive
      oSession.url = oSession.url.Replace(gs_ReplaceToken, gs_ReplaceTokenWith);
    }
    if ((null != gs_OverridenHost) && (oSession.host.toLowerCase() == gs_OverridenHost)) {
      oSession["x-overridehost"] = gs_OverrideHostWith;
    }

    if ((null != bpRequestURI) && oSession.uriContains(bpRequestURI)) {
      oSession["x-breakrequest"] = "uri";
    }

    if ((null != bpMethod) && (oSession.HTTPMethodIs(bpMethod))) {
      oSession["x-breakrequest"] = "method";
    }

    if ((null != uiBoldURI) && oSession.uriContains(uiBoldURI)) {
      oSession["ui-bold"] = "QuickExec";
    }

    if (m_SimulateModem) {
      // Delay sends by 300ms per KB uploaded.
      oSession["request-trickle-delay"] = "300";
      // Delay receives by 150ms per KB downloaded.
      oSession["response-trickle-delay"] = "150";
    }

    if (m_DisableCaching) {
      oSession.oRequest.headers.Remove("If-None-Match");
      oSession.oRequest.headers.Remove("If-Modified-Since");
      oSession.oRequest["Pragma"] = "no-cache";
    }

    // User-Agent Overrides
    if (null != sUA) {
      oSession.oRequest["User-Agent"] = sUA;
    }

    if (m_Japanese) {
      oSession.oRequest["Accept-Language"] = "ja";
    }

    if (m_AutoAuth) {
      // Automatically respond to any authentication challenges using the 
      // current Fiddler user's credentials. You can change (default)
      // to a domain\\username:password string if preferred.
      //
      // WARNING: This setting poses a security risk if remote 
      // connections are permitted!
      oSession["X-AutoAuth"] = "(default)";
    }

    if (m_AlwaysFresh && (oSession.oRequest.headers.Exists("If-Modified-Since") || oSession.oRequest.headers.Exists("If-None-Match"))) {
      oSession.utilCreateResponseAndBypassServer();
      oSession.responseCode = 304;
      oSession["ui-backcolor"] = "Lavender";
    }
  }

  // This function is called immediately after a set of request headers has
  // been read from the client. This is typically too early to do much useful
  // work, since the body hasn't yet been read, but sometimes it may be useful.
  //
  // For instance, see 
  // http://blogs.msdn.com/b/fiddler/archive/2011/11/05/http-expect-continue-delays-transmitting-post-bodies-by-up-to-350-milliseconds.aspx
  // for one useful thing you can do with this handler.
  //
  // Note: oSession.requestBodyBytes is not available within this function!
  /*
  static function OnPeekAtRequestHeaders(oSession: Session) {
  var sProc = ("" + oSession["x-ProcessInfo"]).ToLower();
  if (!sProc.StartsWith("mylowercaseappname")) oSession["ui-hide"] = "NotMyApp";
  }
  */

  //
  // If a given session has response streaming enabled, then the OnBeforeResponse function 
  // is actually called AFTER the response was returned to the client.
  //
  // In contrast, this OnPeekAtResponseHeaders function is called before the response headers are 
  // sent to the client (and before the body is read from the server).  Hence this is an opportune time 
  // to disable streaming (oSession.bBufferResponse = true) if there is something in the response headers 
  // which suggests that tampering with the response body is necessary.
  // 
  // Note: oSession.responseBodyBytes is not available within this function!
  //
  static
  function OnPeekAtResponseHeaders(oSession: Session) {
    //FiddlerApplication.Log.LogFormat("Session {0}: Response header peek shows status is {1}", oSession.id, oSession.responseCode);
    if (m_DisableCaching) {
      oSession.oResponse.headers.Remove("Expires");
      oSession.oResponse["Cache-Control"] = "no-cache";
    }

    if ((bpStatus > 0) && (oSession.responseCode == bpStatus)) {
      oSession["x-breakresponse"] = "status";
      oSession.bBufferResponse = true;
    }

    if ((null != bpResponseURI) && oSession.uriContains(bpResponseURI)) {
      oSession["x-breakresponse"] = "uri";
      oSession.bBufferResponse = true;
    }

    if (oSession.HostnameIs("v.qq.com")) {
      oSession["ui-color"] = "Aqua";
    }
    if (oSession.HostnameIs("livew.l.qq.com")) {
      oSession["ui-color"] = "green";
    }
    if (oSession.HostnameIs("m.v.qq.com")) {
      oSession["ui-color"] = "gray";
    }

  }

  static
  function OnBeforeResponse(oSession: Session) {
    if (m_Hide304s && oSession.responseCode == 304) {
      oSession["ui-hide"] = "true";
    }
    if (sAllowOrigin) {
      oSession.oResponse["Access-Control-Allow-Credentials"] = "true";
      oSession.oResponse["Access-Control-Allow-Origin"] = sAllowOrigin;
    }
  }


  public static BindUIColumn("Time Taken")

  function CalcTimingCol(oSession: Session) {
    var sResult = String.Empty;
    if (oSession.Timers.ServerDoneResponse > oSession.Timers.ClientDoneRequest) {
      sResult = (oSession.Timers.ServerBeginResponse - oSession.Timers.ClientBeginRequest).ToString();
    }
    return sResult;
  }

  public static BindUIColumn("ReginResuestTime", 60)

  function BeginRequestTime(oSession: Session) {
    if (oSession.Timers !== null) {
      return oSession.Timers.ClientBeginRequest.ToString();
    }
    return String.Empty;
  }

  /*
      // This function executes just before Fiddler returns an error that it has 
      // itself generated (e.g. "DNS Lookup failure") to the client application.
      // These responses will not run through the OnBeforeResponse function above.
      static function OnReturningError(oSession: Session) {
      }
  */
  /*
      // This function executes after Fiddler finishes processing a Session, regardless
      // of whether it succeeded or failed. Note that this typically runs AFTER the last
      // update of the Web Sessions UI listitem, so you must manually refresh the Session's
      // UI if you intend to change it.
      static function OnDone(oSession: Session) {
      }
  */

  // The Main() function runs everytime your FiddlerScript compiles
  static
  function Main() {
    var today: Date = new Date();
    FiddlerObject.StatusText = " CustomRules.js was loaded at: " + today;

    // Uncomment to add a "Server" column containing the response "Server" header, if present
    // UI.lvSessions.AddBoundColumn("Server", 50, "@response.server");
    // 显示服务器IP地址
    // FiddlerObject.UI.lvSessions.AddBoundColumn("HostIP", 50, "x-hostIP");

    FiddlerObject.UI.lvSessions.AddBoundColumn("RTime", 50, "111");

    // Uncomment to add a global hotkey (Win+G) that invokes the ExecAction method below...
    // UI.RegisterCustomHotkey(HotkeyModifiers.Windows, Keys.G, "screenshot"); 
  }

  // These static variables are used for simple breakpointing & other QuickExec rules 
  BindPref("fiddlerscript.ephemeral.bpRequestURI")
  public static
  var bpRequestURI: String = null;

  BindPref("fiddlerscript.ephemeral.bpResponseURI")
  public static
  var bpResponseURI: String = null;

  BindPref("fiddlerscript.ephemeral.bpMethod")
  public static
  var bpMethod: String = null;

  static
  var bpStatus: int = -1;
  static
  var uiBoldURI: String = null;
  static
  var gs_ReplaceToken: String = null;
  static
  var gs_ReplaceTokenWith: String = null;
  static
  var gs_OverridenHost: String = null;
  static
  var gs_OverrideHostWith: String = null;

  // The OnExecAction function is called by either the QuickExec box in the Fiddler window,
  // or by the ExecAction.exe command line utility.
  static
  function OnExecAction(sParams: String[]): Boolean {

    FiddlerObject.StatusText = "ExecAction: " + sParams[0];

    var sAction = sParams[0].toLowerCase();
    switch (sAction) {
      case "bold":
        if (sParams.Length < 2) {
          uiBoldURI = null;
          FiddlerObject.StatusText = "Bolding cleared";
          return false;
        }
        uiBoldURI = sParams[1];
        FiddlerObject.StatusText = "Bolding requests for " + uiBoldURI;
        return true;
      case "bp":
        FiddlerObject.alert("bpu = breakpoint request for uri\nbpm = breakpoint request method\nbps=breakpoint response status\nbpafter = breakpoint response for URI");
        return true;
      case "bps":
        if (sParams.Length < 2) {
          bpStatus = -1;
          FiddlerObject.StatusText = "Response Status breakpoint cleared";
          return false;
        }
        bpStatus = parseInt(sParams[1]);
        FiddlerObject.StatusText = "Response status breakpoint for " + sParams[1];
        return true;
      case "bpv":
      case "bpm":
        if (sParams.Length < 2) {
          bpMethod = null;
          FiddlerObject.StatusText = "Request Method breakpoint cleared";
          return false;
        }
        bpMethod = sParams[1].toUpperCase();
        FiddlerObject.StatusText = "Request Method breakpoint for " + bpMethod;
        return true;
      case "bpu":
        if (sParams.Length < 2) {
          bpRequestURI = null;
          FiddlerObject.StatusText = "RequestURI breakpoint cleared";
          return false;
        }
        bpRequestURI = sParams[1];
        FiddlerObject.StatusText = "RequestURI breakpoint for " + sParams[1];
        return true;
      case "bpa":
      case "bpafter":
        if (sParams.Length < 2) {
          bpResponseURI = null;
          FiddlerObject.StatusText = "ResponseURI breakpoint cleared";
          return false;
        }
        bpResponseURI = sParams[1];
        FiddlerObject.StatusText = "ResponseURI breakpoint for " + sParams[1];
        return true;
      case "overridehost":
        if (sParams.Length < 3) {
          gs_OverridenHost = null;
          FiddlerObject.StatusText = "Host Override cleared";
          return false;
        }
        gs_OverridenHost = sParams[1].toLowerCase();
        gs_OverrideHostWith = sParams[2];
        FiddlerObject.StatusText = "Connecting to [" + gs_OverrideHostWith + "] for requests to [" + gs_OverridenHost + "]";
        return true;
      case "urlreplace":
        if (sParams.Length < 3) {
          gs_ReplaceToken = null;
          FiddlerObject.StatusText = "URL Replacement cleared";
          return false;
        }
        gs_ReplaceToken = sParams[1];
        gs_ReplaceTokenWith = sParams[2].Replace(" ", "%20"); // Simple helper
        FiddlerObject.StatusText = "Replacing [" + gs_ReplaceToken + "] in URIs with [" + gs_ReplaceTokenWith + "]";
        return true;
      case "allbut":
      case "keeponly":
        if (sParams.Length < 2) {
          FiddlerObject.StatusText = "Please specify Content-Type to retain during wipe.";
          return false;
        }
        UI.actSelectSessionsWithResponseHeaderValue("Content-Type", sParams[1]);
        UI.actRemoveUnselectedSessions();
        UI.lvSessions.SelectedItems.Clear();
        FiddlerObject.StatusText = "Removed all but Content-Type: " + sParams[1];
        return true;
      case "stop":
        UI.actDetachProxy();
        return true;
      case "start":
        UI.actAttachProxy();
        return true;
      case "cls":
      case "clear":
        UI.actRemoveAllSessions();
        return true;
      case "g":
      case "go":
        UI.actResumeAllSessions();
        return true;
      case "goto":
        if (sParams.Length != 2) return false;
        Utilities.LaunchHyperlink("http://www.google.com/search?hl=en&btnI=I%27m+Feeling+Lucky&q=" + Utilities.UrlEncode(sParams[1]));
        return true;
      case "help":
        Utilities.LaunchHyperlink("http://fiddler2.com/r/?quickexec");
        return true;
      case "hide":
        UI.actMinimizeToTray();
        return true;
      case "log":
        FiddlerApplication.Log.LogString((sParams.Length < 2) ? "User couldn't think of anything to say..." : sParams[1]);
        return true;
      case "nuke":
        UI.actClearWinINETCache();
        UI.actClearWinINETCookies();
        return true;
      case "screenshot":
        UI.actCaptureScreenshot(false);
        return true;
      case "show":
        UI.actRestoreWindow();
        return true;
      case "tail":
        if (sParams.Length < 2) {
          FiddlerObject.StatusText = "Please specify # of sessions to trim the session list to.";
          return false;
        }
        UI.TrimSessionList(int.Parse(sParams[1]));
        return true;
      case "quit":
        UI.actExit();
        return true;
      case "dump":
        UI.actSelectAll();
        UI.actSaveSessionsToZip(CONFIG.GetPath("Captures") + "dump.saz");
        UI.actRemoveAllSessions();
        FiddlerObject.StatusText = "Dumped all sessions to " + CONFIG.GetPath("Captures") + "dump.saz";
        return true;

      default:
        if (sAction.StartsWith("http") || sAction.StartsWith("www.")) {
          System.Diagnostics.Process.Start(sParams[0]);
          return true;
        } else {
          FiddlerObject.StatusText = "Requested ExecAction: '" + sAction + "' not found. Type HELP to learn more.";
          return false;
        }
    }
  }
}

说说safari的video onprogress

测试环境:
Mac: 10.10.3
Safari: 8.0.5
video format: mp4


youtube已经使用html5播放视频很久了,咱们也不能落后太多吧。想必大家也是认为html5 video才是web视频的未来吧。
测试发现,safari的onprogress比较鸡肋,根本不是标准的。只有视频全部cache完才会触发,靠onprogress来设计控制栏已经不能简单兼容多浏览器了。

同属webkit,safari,你不羞耻吗?
官方的文档里的demo,视频还没发播(Http/1.1 Service Unavailable),这么大的厂,不忍直视。。。
其实,没有progress,我们可以用timeupdate + setInterval,切记做好性能优化。其实也是可以实现的。


对照safari,我们发现,mac下的google chrome的表现几乎完美。
测试了一个时长305秒的视频:

  • chrome会缓冲到58秒然后停止缓冲。
  • safari会缓冲全部视频时长
  • firefox也会缓冲全部视频时长

google毕竟是有youtube的存在,对视频的理解更深入,知道浏览器该怎么节省带宽。

参考文档

延伸阅读

hello zobor

hello
自勉!!

用yii搭建一个网站--入门

官方网站:http://www.yiiframework.com/
网站目录:F:\dropbox\public_html

解压yii源码,将framework文件夹copy到 F:\dropbox\public_html

shell>> F:
shell>> cd dropbox\public_html

自动生成站点(lab)目录及文件:

shell>> php framework/yiic.php webapp lab
shell>> ls
framework  lab
shell>> cd lab\proceted

进入yii shell:

shell>> yiic shell ../index.php
Yii Interactive Tool v1.1 (based on Yii v1.1.10)
Please type 'help' for help. Type 'exit' to quit.
>>
shell>> help
At the prompt, you may enter a PHP statement or one of the following commands:
 - controller
 - crud
 - form
 - help
 - model
 - module

Type 'help <command-name>' for details about a command.

To expand the above command list, place your command class files
under 'protected/commands/shell', or a directory specified
by the 'YIIC_SHELL_COMMAND_PATH' environment variable. The command class
must extend from CConsoleCommand.
新建模块(user)module:
shell>> module user
    mkdir F:/Dropbox/public_html/yii/lab/protected/modules
    mkdir F:/Dropbox/public_html/yii/lab/protected/modules/user
    mkdir F:/Dropbox/public_html/yii/lab/protected/modules/user/components
    mkdir F:/Dropbox/public_html/yii/lab/protected/modules/user/controllers
   generate controllers/DefaultController.php
    mkdir F:/Dropbox/public_html/yii/lab/protected/modules/user/messages
    mkdir F:/Dropbox/public_html/yii/lab/protected/modules/user/models
    mkdir F:/Dropbox/public_html/yii/lab/protected/modules/user/views
    mkdir F:/Dropbox/public_html/yii/lab/protected/modules/user/views/default
   generate views/default/index.php
    mkdir F:/Dropbox/public_html/yii/lab/protected/modules/user/views/layouts
   generate UserModule.php

Module 'user' has been created under the following folder:
  F:\Dropbox\public_html\yii\lab\protected\modules\user

You may access it in the browser using the following URL:
  http://hostname/path/to/index.php?r=user

Note, the module needs to be installed first by adding 'user'
to the 'modules' property in the application configuration.
新建模型model:
shell>> help model
USAGE
  model <class-name> [table-name]

DESCRIPTION
  This command generates a model class with the specified class name.

PARAMETERS
 * class-name: required, model class name. By default, the generated
   model class file will be placed under the directory aliased as
   'application.models'. To override this default, specify the class
   name in terms of a path alias, e.g., 'application.somewhere.ClassName'.

   If the model class belongs to a module, it should be specified
   as 'ModuleID.models.ClassName'.

   If the class name ends with '*', then a model class will be generated
   for EVERY table in the database.

   If the class name contains a regular expression deliminated by slashes,
   then a model class will be generated for those tables whose name
   matches the regular expression. If the regular expression contains
   sub-patterns, the first sub-pattern will be used to generate the model
   class name.

 * table-name: optional, the associated database table name. If not given,
   it is assumed to be the model class name.

   Note, when the class name ends with '*', this parameter will be
   ignored.

EXAMPLES
 * Generates the Post model:
      model Post

 * Generates the Post model which is associated with table 'posts':
      model Post posts

 * Generates the Post model which should belong to module 'admin':
      model admin.models.Post

 * Generates a model class for every table in the current database:
      model *

 * Same as above, but the model class files should be generated
   under 'protected/models2':
      model application.models2.*

 * Generates a model class for every table whose name is prefixed
   with 'tbl_' in the current database. The model class will not
   contain the table prefix.
      model /^tbl_(.*)$/

 * Same as above, but the model class files should be generated
   under 'protected/models2':
      model application.models2./^tbl_(.*)$/

注:模型用shell还没搞定,shell到此。接下来用gii来新建模型

shell>> vim protected/config/main.php
'gii'=>array(
       'class'=>'system.gii.GiiModule',
       'password'=>'123456',
          // If removed, Gii defaults to localhost only. Edit carefully to taste.
       'ipFilters'=>array('127.0.0.1','127.0.0.5','::1'),
     ),

‘user’,//模块都得在这里设置下
设置域名和密码就可以了,浏览器打开:
http://127.0.0.5/public_html/lab/index.php?r=gii/default/login
输入密码:123456
点击“Model Generator”
填写相关参数即可~~~

shell>> vim protected\modules\user\controllers\DefaultController.php

修改actionIndex:

$u =new User();
$list = $u->findAll();
var_dump($list);

打开http://127.0.0.5/public_html/lab/index.php?r=user
OK~~~

ERROR:
CDbConnection failed to open the DB connection: could not find driver

resolve:php缺少pdo_mysql拓展

MongoDb命令--入门

启动和鉴权登录

C:\Documents and Settings\Administrator>mongo
MongoDB shell version: 1.8.1
connecting to: test
> use admin
switched to db admin
> db.auth('root',123456)
1
> show dbs
admin   0.03125GB
kisscss 0.03125GB
local   (empty)
platform      0.03125GB
testdb  0.03125GB
> use kisscss
switched to db kisscss
> show tables
a
foo
system.indexes
system.users
> show collections
a
foo
system.indexes
system.users
> db.addUser('root',111111)
{
      "user" : "root",
      "readOnly" : false,
      "pwd" : "2235ba5209b51a08f63d99b39281c45a"
}

CRUD

CRUD是指在做计算处理时的增加(Create)、查询(Retrieve)(重新得到数据)、更新(Update)和删除(Delete)几个单词的首字母简写

> use kisscss
switched to db kisscss
> db.dropDatabase()
{ "dropped" : "kisscss", "ok" : 1 }
> db.peoples.insert({name:'zhangheng',age:25})

> db.peoples.find()
{ "_id" : ObjectId("504071bf47dcb049fdb047ed"), "name" : "zhangheng", "age" : 25 }
> db.peoples.ensureIndex({name:1},{unique:true})
> db.system.indexes.find()
{ "name" : "_id_", "ns" : "java.user", "key" : { "_id" : 1 }, "v" : 0 }
{ "name" : "_id_", "ns" : "java.peoples", "key" : { "_id" : 1 }, "v" : 0 }
{ "_id" : ObjectId("5040721747dcb049fdb047ee"), "ns" : "java.peoples", "key" : { "name" : 1 }, "name" : "name_1", "unique" : true, "v" : 0 }
> db.peoples.insert({name:'zhangheng'})
E11000 duplicate key error index: java.peoples.$name_1  dup key: { : "zhangheng" }

> db.peoples.find({name:'zhang'})
{ "_id" : ObjectId("504074a347dcb049fdb047f4"), "name" : "zhang", "age" : 30 }
> db.peoples.find()
{ "_id" : ObjectId("504071bf47dcb049fdb047ed"), "name" : "zhangheng", "age" : 25 }
{ "_id" : ObjectId("504074a347dcb049fdb047f4"), "name" : "zhang", "age" : 30 }
{ "_id" : ObjectId("5040759a47dcb049fdb047f5"), "name" : "zhangh", "age" : 100 }
{ "_id" : ObjectId("504075ac47dcb049fdb047f6"), "name" : "ZHANGHENG", "age" : 50 }
{ "_id" : ObjectId("5040760b47dcb049fdb047f7"), "name" : "kisscss", "age" : 60 }
> db.peoples.find({age:{$gt:50,$lt:100}})
{ "_id" : ObjectId("5040760b47dcb049fdb047f7"), "name" : "kisscss", "age" : 60 }
> var jsfun = function(){ return this.name.indexOf('zhang')!= -1; }
> db.peoples.find({$where:jsfun})
{ "_id" : ObjectId("504071bf47dcb049fdb047ed"), "name" : "zhangheng", "age" : 25 }
{ "_id" : ObjectId("504074a347dcb049fdb047f4"), "name" : "zhang", "age" : 30 }
{ "_id" : ObjectId("5040759a47dcb049fdb047f5"), "name" : "zhangh", "age" : 100 }
> db.peoples.find({name:/.*zhang.*/})
{ "_id" : ObjectId("504074a347dcb049fdb047f4"), "name" : "zhang", "age" : 30 }
{ "_id" : ObjectId("5040759a47dcb049fdb047f5"), "name" : "zhangh", "age" : 100 }
{ "_id" : ObjectId("504071bf47dcb049fdb047ed"), "name" : "zhangheng", "age" : 25 }

> db.peoples.find()
{ "_id" : ObjectId("504071bf47dcb049fdb047ed"), "name" : "zhangheng", "age" : 25 }
{ "_id" : ObjectId("504074a347dcb049fdb047f4"), "name" : "zhang", "age" : 30 }
{ "_id" : ObjectId("5040759a47dcb049fdb047f5"), "name" : "zhangh", "age" : 100 }
{ "_id" : ObjectId("504075ac47dcb049fdb047f6"), "name" : "ZHANGHENG", "age" : 50 }
{ "_id" : ObjectId("5040760b47dcb049fdb047f7"), "name" : "kisscss", "age" : 60 }
> db.peoples.update({name:'arvin'},{age:32},false)
> db.peoples.find()
{ "_id" : ObjectId("504071bf47dcb049fdb047ed"), "name" : "zhangheng", "age" : 25 }
{ "_id" : ObjectId("504074a347dcb049fdb047f4"), "name" : "zhang", "age" : 30 }
{ "_id" : ObjectId("5040759a47dcb049fdb047f5"), "name" : "zhangh", "age" : 100 }
{ "_id" : ObjectId("504075ac47dcb049fdb047f6"), "name" : "ZHANGHENG", "age" : 50 }
{ "_id" : ObjectId("5040760b47dcb049fdb047f7"), "name" : "kisscss", "age" : 60 }
> db.peoples.update({name:'arvin'},{age:32},true)
> db.peoples.find()
{ "_id" : ObjectId("504071bf47dcb049fdb047ed"), "name" : "zhangheng", "age" : 25 }
{ "_id" : ObjectId("504074a347dcb049fdb047f4"), "name" : "zhang", "age" : 30 }
{ "_id" : ObjectId("5040759a47dcb049fdb047f5"), "name" : "zhangh", "age" : 100 }
{ "_id" : ObjectId("504075ac47dcb049fdb047f6"), "name" : "ZHANGHENG", "age" : 50 }
{ "_id" : ObjectId("5040760b47dcb049fdb047f7"), "name" : "kisscss", "age" : 60 }
{ "_id" : ObjectId("50407799cf84312a7594d350"), "age" : 32 }