<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

        這一節主要是介紹局部狀態變量,介紹了set!和begin的語法,看來ruby使用!號來表示改變變量值不是什么新鮮主意。
      
    習題3.1,不解釋了
    ;習題3.1
    (define (make-accumulator init)
      (define (accumulator num)
        (set! init (+ init num))
        init)
      accumulator)

    習題3.2,非常有趣的例子,在內部維持一個計數的變量即可,如果傳入的參數是特定的符號就返回計數或者清0,如果不是,原過程調用。

    ;習題3.2
    (define (make-monitored proc)
       (let ((counter 0))
      (define (proc-monitor args)
             (cond ((eq? args 'how-many-calls?) counter)
                ((eq? args 'reset-count) (begin (set! counter 0) counter))
                (else
                  (begin (set! counter (+ counter 1)) (proc args)))))
      proc-monitor))

    請注意,我的實現只能針對有一個參數的過程,對于多個參數的過程我還不知道怎么做。

    習題3.3,passwd的局部狀態變量,在dispatch前比較下傳入的密碼是否與之一致

    ;習題3.3
    (define (make-account balance passwd)
      (define (withdraw amount)
        (if (>= balance amount)
            (begin (set! balance (- balance amount)) balance)
            "余額不足"))
      (define (deposit amount)
        (set! balance (+ balance amount))
        balance)
      (define (dispatch pwd m)
        (if (eq? pwd passwd)
            (cond ((eq? m 'withdraw) withdraw)
                  ((eq? m 'deposit) deposit)
                (else
                   (error "Unknow request--MAKE-ACCOUNT" m)))
            (lambda(x) "Incorrect password")))
            
      dispatch)
    不一致的時候,返回一個匿名過程,僅僅是輸出消息Incorrect password

    習題3.4,在內部維持一個局部變量counter,用于計數密碼錯誤的次數,在dispatch前判斷counter是否等于7,如果是7就調用過程call-the-cops。

    ;習題3.4
    (define (make-account balance passwd)
      (let ((counter 0))
      (define (withdraw amount)
        (if (>= balance amount)
            (begin (set! balance (- balance amount)) balance)
            "余額不足"))
      (define (deposit amount)
        (set! balance (+ balance amount))
        balance)
      (define (call-the-cops amount)
        "您已經嘗試輸入密碼7次了!不能再試!")
      (define (dispatch pwd m)
        (cond ((= 7 counter) call-the-cops)
              ((eq? pwd passwd)
               (cond ((eq? m 'withdraw) withdraw)
                     ((eq? m 'deposit) deposit)
                     (else
                       (error "Unknow request--MAKE-ACCOUNT" m))))
              (else
                (begin (set! counter (+ counter 1)) (lambda(x) "Incorrect password")))))
     dispatch))




    posted @ 2007-07-24 17:12 dennis 閱讀(310) | 評論 (0)編輯 收藏

        暫時搞不到《Programming Erlang》,最近就一直在看Erlang自帶的例子和Reference Manual。基礎語法方面有一些過去遺漏或者沒有注意的,斷斷續續僅記于此。

    1。Erlang的保留字有:

    after and andalso band begin bnot bor bsl bsr bxor case catch cond div end fun if let not of or orelse query receive rem try when xor

    基本都是些用于邏輯運算、位運算以及特殊表達式的符號

    2.Erlang的類型,除了在前面入門一提到的類型外,還包括:
    1)Binary,用于表示某段未知類型的內存區域
    比如:
    1> <<10,20>>.
    <<10,20>>
    2> <<"ABC">>.
     <<65,66,67>>

    2)Reference,通過調用mk_ref/0產生的運行時的unique term

    3)String,字符串,Erlang中的字符串用雙引號包括起來,其實也是list。編譯時期,兩個鄰近的字符串將被連接起來,比如"string" "42" 等價于 "string42"

    4)Record,記錄類型,與c語言中的struct類似,模塊可以通過-record屬性聲明,比如:
    -module(person).
    -export([new/2]).
    -record(person, {name, age}).
    new(Name, Age) ->
         #person{name=Name, age=Age}.
    1> person:new(dennis, 44).
    {person,dennis,44}
     在編譯后其實已經被轉化為tuple。可以通過Name#person.name來訪問Name Record的name屬性。

    3.模塊的預定義屬性
    -module(Module).    聲明模塊名稱,必須與文件名相同
    -export(Functions).   指定向外界導出的函數列表
    -import(Module,Functions).   引入函數,引入的函數可以被當作本地定義的函數使用
    -compile(Options).     設置編譯選項,比如export_all
    -vsn(Vsn).         模塊版本,設置了此項,可以通過beam_lib:version/1 獲取此項信息
    可以通過-include和-include_lib來包含文件,兩者的區別是include-lib不能通過絕對路徑查找文件,而是在你當前Erlang的lib目錄進行查找。

    4.try表達式,try表達式可以與catch結合使用,比如:
    try Expr
    catch
    throw:Term -> Term;
    exit:Reason -> {'EXIT',Reason}
    error:Reason -> {'EXIT',{Reason,erlang:get_stacktrace()}}
    end

    不僅如此,try還可以與after結合使用,類似java中的try..finally,用于進行清除作用,比如:
    termize_file(Name) -> {ok,F} = file:open(Name, [read,binary]), try {ok,Bin} = file:read(F, 1024*1024), binary_to_term(Bin) after file:close(F) end.

    5.列表推斷(List Comprehensions),函數式語言特性之一,Erlang中的語法類似:
    [Expr || Qualifier1,...,QualifierN] Expr可以是任意的表達式,而Qualifier是generator或者filter。還是各舉例子說明下。
    1> [X*2 || X <- [1,2,3]]. [2,4,6]

    2> L=[1,2,3,4,5,6,7].
    [1,2,3,4,5,6,7]
    3> [X|X<-L,X>=3].
    [
    3,4,5,6,7]

    再看幾個比較酷的例子,來自Programming Erlang
    比如快速排序
    -module(qsort).
    -export([qsort/1]).
    qsort([])->[];
    qsort([Pivot|T])->
      qsort([X||X<-T,X<Pivot])
       ++ [Pivot] ++
      qsort([X||X<-T,X>=Pivot]).

    搜索勾股數組
    %勾股數組
    -module(pythag).
    -export([pythag/1]).
    pythag(N)->
        L=lists:seq(1,N),
        Square=fun(X) when is_number(X)->X*X end,
        [{A,B,C}||
            A<-L,
            B<-L,
            C<-L,
            A+B+C=<N,
            Square(A)+Square(B)=:=Square(C)].
    列表推斷將大大減少你的敲擊鍵盤的次數。
     
    6.宏,定義常量或者函數等等,語法如下:
    -define(Const, Replacement). -define(Func(Var1,...,VarN), Replacement).
    使用的時候在宏名前加個問號?,比如?Const,Replacement將插入宏出現的位置。系統預定義了一些宏:
    ?MODULE 表示當前模塊名

    ?MODULE_STRING 同上,但是以字符串形式
    ?FILE 當前模塊的文件名
    ?LINE 調用的當前代碼行數
    ?MACHINE 機器名

    Erlang的宏與C語言的宏很相似,同樣有宏指示符,包括:
    -undef(Macro).
    取消宏定義
    -ifdef(Macro).
    當宏Macro有定義的時候,執行以下代碼
    -ifndef(Macro).
    同上,反之
    -else.
    接在ifdef或者ifndef之后,表示不滿足前者條件時執行以下代碼
    -endif.
    if終止符
    假設宏-define(Square(X),X*X).用于計算平方,那么??X將返回X表達式的字符串形式,類似C語言中#arg

    一個簡單的宏例子:
    -module(macros_demo).
    -ifdef(debug).
    -define(LOG(X), io:format("{~p,~p}: ~p~n", [?MODULE,?LINE,X])).
    -else.
    -define(LOG(X), true).
    -endif.
    -define(Square(X),X*X).
    -compile(export_all).
    test()
    ->
        A
    =3,
        ?LOG(A),
        B
    =?Square(A),
        io:format(
    "square(~w) is ~w~n",[A,B]).
    當編譯時不開啟debug選項的時候:
    17> c(macros_demo).
    {ok,macros_demo}
    18> macros_demo:test().
    square(3) is 9

    當編譯時開啟debug之后:

    19> c(macros_demo,{d,debug}).
    {ok,macros_demo}
    20> macros_demo:test().
    {macros_demo,11}: 3
    square(3) is 9
    ok

    可以看到LOG的輸出了,行數、模塊名以及參數
    7、Process Dictionary,每個進程都有自己的process dictionary,用于存儲這個進程內的全局變量,可以通過下列
    BIFs操作:
    put(Key, Value)
    get(Key)
    get()
    get_keys(Value)
    erase(Key)
    erase()

    8、關于分布式編程,需要補充的幾點
    1)節點之間的連接默認是transitive,也就是當節點A連接了節點B,節點B連接了節點C,那么節點A也與節點C互相連接
    可以通過啟動節點時指定參數-connect_all false來取消默認行為

    2)隱藏節點,某些情況下,你希望連接一個節點而不去連接其他節點,你可以通過在節點啟動時指定-hidden選項
    來啟動一個hidden node。在此情況下,通過nodes()查看所有連接的節點將不會出現隱藏的節點,想看到隱藏的節點
    可以通過nodes(hidden)或者nodes(connected)來查看。

    完整的erl選項如下:
    -connect_all false 上面已經解釋。
    -hidden 啟動一個hidden node
    -name Name 啟動一個系統成為節點,使用long name.
    -setcookie Cookie Erlang:set_cookie(node(), Cookie).相同,設置magic cookie
    -sname Name 啟動一個Erlang系統作為節點,使用short name

    注意,short name啟動的節點是無法與long name節點通信的

    9.一個小細節,在Erlang中小于等于是用=<表示,而不是一般語言中的<=語法,我犯過錯誤的地方,同樣,不等于都是用/號,而不是
    !,比如/=、=/=。

    10.and or 和andalso orelse的區別

    and和or會計算兩邊的表達式,而andalso和orelse的求值采用短路機制,比如exp1 andalso exp2,當exp1返回false之后,就不會去求值
    exp2,而是直接返回false,而exp1 and exp2會對exp1和exp2都進行求值,or與orelse也類似。
     
    今天在erlang-china下到了《Programming Erlang》,準備打印一份看看,進入OTP的學習。  


     
     





    posted @ 2007-07-24 11:23 dennis 閱讀(8370) | 評論 (0)編輯 收藏

        來自sicp的完整代碼,包括書中給出的代碼以及習題,實現了huffman樹的生成、解碼、編碼過程,總共67行代碼,同樣的代碼有空用java、ruby改寫下,看看會有什么不同。
    (define (make-leaf symbol weight)
      (list 
    'leaf symbol weight))
    (define (leaf? object)
      (eq? (car object) 
    'leaf))
    (define (symbol-leaf x) (cadr x))
    (define (weight
    -leaf x) (caddr x))
    ;合并最低權重的兩個節點
    (define (make
    -code-tree left right)
      (list left right (append (symbols left) (symbols right)) (
    + (weight left) (weight right))))
    (define (left
    -branch tree) (car tree))
    (define (right
    -branch tree) (cadr tree))
    (define (symbols tree)
      (
    if (leaf? tree)
          (list (symbol
    -leaf tree))
          (caddr tree)))
    (define (weight tree)
      (
    if (leaf? tree)
          (weight
    -leaf tree)
          (cadddr tree)))
    ;解碼
    (define (decode bits tree)
      (define (decode
    -1 bits current-branch)
        (
    if (null? bits)
            
    '()
            (let ((next-branch
                  (choose
    -branch (car bits) current-branch)))
              (
    if (leaf? next-branch)
                  (cons (symbol
    -leaf next-branch)
                        (decode
    -1 (cdr bits) tree))
                  (decode
    -1 (cdr bits) next-branch)))))
      (decode
    -1 bits tree))
    (define (choose
    -branch bit branch)
      (cond ((
    = bit 0) (left-branch branch))
            ((
    = bit 1) (right-branch branch))
            (
    else (display "bad bit --CHOOSE-BRANCH"))))
    (define (adjoin
    -set x set)
      (cond ((null? set) (list x))
            ((
    < (weight x) (weight (car set))) (cons x set))
            (
    else
               (cons (car set) (adjoin
    -set x (cdr set))))))
    (define (make
    -leaf-set pairs)
      (
    if (null? pairs)
          
    '()
          (let ((pair (car pairs)))
            (adjoin
    -set (make-leaf (car pair) (cadr pair)) (make-leaf-set (cdr pairs))))))

    ;編碼
    (define (encode message tree)
      (
    if (null? message)
          
    '()
          (append (encode-symbol (car message) tree)
                  (encode (cdr message) tree))))
    (define (encode
    -symbol symbol tree)
      (define (iter branch)
        (
    if (leaf? branch)
            
    '()
            (if (memq symbol (symbols (left-branch branch)))
                (cons 0 (iter (left
    -branch branch)))
                (cons 
    1 (iter (right-branch branch))))
            ))
      (
    if (memq symbol (symbols tree))
          (iter tree)
          (display 
    "bad symbol -- UNKNOWN SYMBOL")))
    ;生成hufman樹
    (define (generate
    -huffman-tree pairs)
      (successive
    -merge (make-leaf-set pairs)))

    (define (successive
    -merge leaf-set)
      (
    if (null? (cdr leaf-set))
          (car leaf
    -set)
          (successive
    -merge (adjoin-set (make-code-tree (car leaf-set)
                                                        (cadr leaf
    -set))
                                        (cddr leaf
    -set)))))



    posted @ 2007-07-23 08:56 dennis 閱讀(976) | 評論 (0)編輯 收藏


        這一節那是相當的有趣,抽象數據的多重表示:采用標志(tag)來區分和數據導向(data-directed)技術,稍微提了下消息傳遞。通過一張二維表格將類型、操作的分派機制介紹的很清楚,靜態OO語言正是通過類型來決定消息的分派,而消息傳遞以列進行劃分,每個類型都以過程來表征,也就是所謂的“智能數據對象”,兩者各有優缺點。當類型增加頻繁時,消息傳遞風格的分派更容易擴展,當操作增加頻繁時,反而是顯式的類型分派更為容易擴展,這一點如果有OO設計經驗應該很容易體會。
    看看習題:

    習題2.73,將求導程序以數據導向方式進行修改:
    a)題目已經說了,基于被求導表達式的類型進行分派,加法表達式或者乘法表達式都有標志來區分,而number?和variable?并沒有標志進行區分,因此無法加入數據導向分派。
    b)選擇函數不變,將求導過程提取出來,根據表達式類型劃分,然后用put過程安裝:
    (define (deriv-sum exp var)
      (make
    -sum (deriv (addend exp) var)
                (deriv (augend 
    exp) var)))

    (define (deriv
    -prod exp var)
      (make
    -sum
       (make
    -product (multiplier exp)
                     (deriv (multiplicand 
    exp) var))
       (make
    -product (deriv (multiplier exp) var)
                     (multiplicand 
    exp))))

    (define (install
    -deriv-package)
      (put 
    'deriv '+ deriv-sum)
      (put 
    'deriv '* deriv-prod)
      
    'done)

    c)我沒做,不過和b差不了多少

    習題2.75,很簡單,跟著書上來:
    (define (make-from-mag-ang r a)
      (define (dispatch op)
        (cond ((eq
    ? op 'real-part) (* r (cos a)))
              ((eq? op 
    'imag-part) (* r (sin a)))
              ((eq
    ? op 'magnitude) r)
              ((eq? op 
    'angle) a)
              (
    else
                 display 
    "Unknow op")))
      dispatch)
    將極角坐標系表示的復數用dispatch過程來表示,這正是消息傳遞風格。

    習題2.76,在本文開頭已經提了。

    posted @ 2007-07-20 14:32 dennis 閱讀(546) | 評論 (0)編輯 收藏

        先讓我們來了解下柏拉圖對世界的理解,柏拉圖認為,自然界中有形的東西是流動的,但是構成這些有形物質的“形式”或“理念”卻是永恒不變的。柏拉圖指出,當我們說到“馬”時,我們沒有指任何一 匹馬,而是稱任何一種馬。而“馬”的含義本身獨立于各種馬(“有形的”),它不存在于空間和時間中,因此是永恒的。但是某一匹特定的、有形的、存在于感官 世界的馬,卻是“流動”的,會死亡,會腐爛。柏拉圖把這個永恒不變的“形式”稱為“理型”,他認為這個世界分為兩個部分,一部分是完美的由“理型”組成的世界,另一個就是我們現實的“粗糙”的世界,真實世界是按照理型世界的標準設計的,總是努力達致完美的理型世界,但總是存有偏差。 因此他相信人類的靈魂是不朽的,靈魂蘇醒后會向往回到完美“理型”的世界,人生來就有“理型”的觀念。總之,柏拉圖深信“理性”遠比“感官”可靠。而他的學生亞里士多德卻反駁他的老師,在亞里士多德看來,他也贊成世界是有變化的“質料”與不變的“形式”組成,比如具體的某只馬是有一些“質料”組成,它有馬的“形式”在里頭,因此它被稱為馬。而“形式”存在于具體的“物”之中,比如“馬”的含義就存在具體的千千萬萬只馬之中, “形式”的觀念并不是人與生俱來的,而是借助于“感官”去感知外界事物而得來的。他把這種“形式”更多地稱為“特征”,由此提出了他的自然界分類觀點,對“物”分類依據的是它能做什么以及它有什么特征。可以說,亞里士多德比他的老師更相信“感官”,沒有像他的老師那樣陷入對完美“理型世界”的眷念而不可自拔。
        聯想到我們在使用靜態OO語言(比如java)試圖去描述現實世界的場景,我們總是試圖先設計出一些類(class),這些類秉承我們的意志,我們預期它們能完美地描述事物,并且試圖去符合所有的現實的場景。可以注意到,這樣的想法不正是柏拉圖式的偏執?我們用頭腦中出現的“理型”(具體到語言中的類)去描述現實世界,可現實世界往往是模糊的、粗糙的,兩者的沖突不可避免,導致類不再按照我們的設想發展,它變的龐大,變的不是那么清晰,因此我們又造出“設計模式”“重構”的“詭辯之術”去彌補、去完整,可這并不是治本之道。首先我們必須承認世界是不完美的,完美的“理型”或者說完美的類是不存在的,類型的劃分不能依賴于頭腦中的完美“理型”(類型的劃分不是取決于類),而應該根據事物的特征以及事物能做什么來劃分。放棄對類描述世界的追求,轉而構造模糊的類型,對象的類型不再預先構造,它的類型取決于它能干什么,它有什么特征,這正是動態語言中的“Duck-Typing”以及一些函數式語言中的模式匹配希望做到的,兩者都是為了描述模糊的現實世界。再比如ruby中的mixin和open class特性又提供了方式讓我們去慢慢完善“粗糙”的類,放棄一蹴而就,選擇有機成長。
        不是很清晰的想法,只是看《蘇菲的世界》里對希臘古典哲學的描述突然想到的,各位權當荒唐言。


    posted @ 2007-07-17 09:20 dennis 閱讀(1553) | 評論 (8)編輯 收藏

        portal開發的一個重要工作就是portlet的開發,網上一大堆hello world,都是最簡單的,用PrintWriter輸出字符串。今天介紹一下稍微復雜的,用戶轉到portlet的edit Model,該頁面是有一個輸入框和一個按鈕,輸入你的名字,然后提交,將轉到此portlet的view Model并輸出hello,your name。
        portlet與servlet非常相似,因為portlet就是在servlet規范的基礎上擴展的,并且portlet容器也是在servlet容器的基礎上擴展,同serlvet一樣,我們的HelloWorldPorlet需要強制繼承自GenericPortlet類,GenericPortlet實現了Portlet接口,看看完整代碼:
    package net.rubyeye.portlets;
    import javax.portlet.ActionResponse;
    import javax.portlet.GenericPortlet;
    import javax.portlet.PortletException;
    import javax.portlet.PortletRequestDispatcher;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;

    public class HelloWorldPortlet extends GenericPortlet {

            
    @Override
            protected void doEdit(RenderRequest req
    , RenderResponse res)
                            throws PortletException
    , IOException {
                    res
    .setContentType("text/html");
                    
    //獲取初始參數,在init-param中定義
                    String jspName 
    = getPortletConfig().getInitParameter("edit-jsp");
                    PortletRequestDispatcher rd 
    = getPortletContext().getRequestDispatcher(
                                    jspName);
                    rd
    .include(req, res);
            }

            
    @Override
            protected void doView(RenderRequest req
    , RenderResponse res)
                            throws PortletException
    , IOException {
                    res
    .setContentType("text/html");
                    
    //執行完processAction后設置了renderParamter,這里得到
                    String msg 
    = req.getParameter("msg");
                   
                    PrintWriter out 
    = res.getWriter();
                    
    System.out.println(msg);
                    
    //有就輸出
                    
    if (msg != null)
                            out
    .write(msg);
                    
    //默認輸出是Hello World
                    
    else
                            out
    .write("Hello World!View!");

            }
            
    //actionURL調用的processAction
            
    @Override
            public void processAction(ActionRequest req
    , ActionResponse res)
                            throws PortletException
    , IOException {
                    
    // TODO Auto-generated method stub
                    String name 
    = req.getParameter("name");
                    
    System.out.println(name);
                    res
    .setRenderParameter("msg", "hello," + name);
            }
    }
        解釋下代碼,portlet默認有三種Model:view、edit和help,顧名思義分別對照瀏覽、編輯和幫助狀態,其中只有view是必須的,當然還可以自定義model。在portlet就有相應的doXXX方法用于呈現相應的片段,portlet還有一個render(RenderRequest,RenderResponse),這個方法與doView等方法的關系類似serlvet中service與doGet、doHelp的關系,一般我們都不直接覆寫render,而是實現具體的doXXX方法。回到這個例子,HelloWorldPortlet有兩個Model:view和edit。
        在doView方法中很簡單,首先需要設置ContentType,然后獲取前面processAction設置的renderParamter,當然,一開始進入portlet是view,這個值根本沒有,默認就用PrintWriter輸出Hello World。
        processAction用于處理ActionRequest的方法,和一般的servlet編程沒有什么不同,請注意,processAction執行之后才是執行相應的render方法,并且與render不共享parameter,因此為了在doView中獲得msg參數,我們需要通過ActionResponse的setRenderParameter來設定RenderRequest的Parameter。
        doEdit方法就比較簡單了,通過PortletConfig的getInitParameter(與ServletConfig一樣了)獲得屬性edit-jsp的值——編輯頁面的位置,然后將該頁面include進portlet。
        portlet需要一個配置文件來告訴portlets容器具體信息,這個文件同樣放在WEB-INF目錄下,并且名為portlet.xml:
    <?xml version="1.0" encoding="UTF-8"?>
    <portlet-app version="1.0"
            xmlns
    ="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
            xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance">

            
    <portlet>
                    
    <portlet-name>HelloWorldPorlet_1</portlet-name>
                    
    <portlet-class>
                            net.rubyeye.porlets.HelloWorldPorlet
                    
    </portlet-class>
                    
    <init-param>
                            
    <name>edit-jsp</name>
                            
    <value>/portlets/edit.jsp</value>
                    
    </init-param>
                    
    <supports>
                            
    <mime-type>text/html</mime-type>
                            
    <portlet-mode>view</portlet-mode>
                            
    <portlet-mode>edit</portlet-mode>
                    
    </supports>
                    
    <portlet-info>
                            
    <title>HelloWorld</title>
                    
    </portlet-info>
            
    </portlet>
    </portlet-app>
      信息非常清楚,就不多做解釋了,edit-jsp的值是/portlets/edit.jsp,portlets容器就會去portlets目錄下尋找edit.jsp。supports元素指定了portlet支持的Model以及Mime類型。更詳細的配置請參考官方規范
       最后就是edit.jsp,需要用到portlets規范規定的標簽,我們這里用到了actionURL,該標簽用于form的action的生成,觸發帶有參數的request請求的processAction調用,當然還有一個renderURL,顧名思義僅是用于呈現,而非action的觸發。請注意,form的method必須是post,因為portlets容器可能將一些狀態信息寫在url,使用post提交避免沖突。
    <%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
    <portlet:defineObjects/>
    <div>
    <form method="post" action="<portlet:actionURL portletMode="view" windowState="normal"/>" >
    please input your name:
    <input type="text" name="name" size="10"/>
    <input type="submit" value="submit"/>
    </form>

      在使用portlet規范規定的標簽前,一定要先使用<portlet:defineObjects/> 標簽,以便定義下列變量讓jsp使用:
    renderRequest
    renderResponse
    portletConfig

        我們通過actionURL標簽產生指向本portlet的url,并且指定沒有錯誤發生時這個portlet應該具有的Model是view,窗口大小為normal。最后部署并運行,因為不同的portal的部署方式和所需要的其他配置文件各不相同,這里就不詳細介紹了。下面是在Bea Portal 10.0上的效果圖:

    1.一開始看到的是view Model,輸出Hello World!View!:


    2.點擊左上角的edit鏈接進入edit model:


    3.輸入dennis,提交,轉到view model:


    posted @ 2007-07-15 21:02 dennis 閱讀(4833) | 評論 (1)編輯 收藏

        這兩天將網上下載的《JSR168 porlet標準手冊漢化整理》和《Liferay Portal二次開發指南》認認真真地看了幾遍,看了BEA站點上portal的getting start,寫了hello world,算是正式開始學習portal了。感謝這么多人無私地分享知識。抄書。

    第一節 Portal 規范
    隨著Portal 的興起,越來越多的公司開始涉足Portal 產品開發,并組建各自的Portal 組
    件和基于其的產品,比如IBM、BEA、MicroSoft、SAP、Apache 等。各個廠商的接口互不
    兼容,給軟件開發商以及開發人員帶來諸多不便。
    1.1.1 JSR168
    為此,JCP 組織發布了JSR168(Java Specification Request),Portlet Specification V1.0,
    用來提供不同的Portal 和Portlet 之間的互通性。只要開發的Portlet 遵循JSR168,則就可以
    在所有遵循JSR168 的Portal 上部署運行。
    JSR168 中定義了Portal 的實現規范和接口,并對理想的Portlet 進行了詳細的規劃和描
    述。
    1.1.2 WSRP
    WSRP 是OASIS Web Service for Remote Portlet 的縮寫。WSRP 是Web Service 的一種新
    的商業應用,一種新的標準,主要用來簡化Portal 對于各種資源或者程序整合的復雜度,可
    以避免編程帶來的整合麻煩和問題。而且Portal 管理員可以從海量的WSRP 服務中選擇需
    要的功能用以整合到目前所用的Portal 中。它有三種角色:
    ①、生產者 ?? 提供Portlet
    ②、消費者 ?? 使用Portlet
    ③、終端用戶 ?? 最終用戶
    它的特點在于生產者將消費者所需要的信息通過WSRP 返回給消費者,這些信息是相對
    標記片斷,例如HTML、XHTML 等,可以直接嵌入用戶的頁面中,而不用像Web Service
    一樣開發用戶端接口。
    實現這個規范,Portal 可以跟各式各樣的數據源打交道,徹底終結信息孤島的窘境。
    第二節 什么是Portal
    Portal 是基于Web 的,以“應用整合”和“消除信息孤島”為最終目的,提供單點登
    錄、內容聚合、個性化門戶定制等功能的綜合信息系統。
    完整的Portal 通常由Portal 服務器、Portlet 容器、Portlet 構成。
    1.2.1 Portal 服務器
    Portal 服務器是容納Portlet 容器,支持Portlet 呈現的普通或者特殊Web 服務器。
    Portal 服務器通常會提供個性化設置、單點登錄、內容聚合、信息發布、權限管理等功能,
    支持各種信息數據來源,并將這些數據信息放在網頁中組合而成,提供個性化的內容定制,
    不同權限的瀏覽者能夠瀏覽不同的信息內容。通常,Portal 提供以下功能:
    單點登錄:Portal 通常采用ACL、SSL、LDAP 等業界標準的安全技術,提供對所有現有
    應用系統的安全集成,只需在Portal 的唯一入口上登錄一次,就可以訪問所有應用系統和
    數據。對于安全性要求較高的應用系統,如電子商務平臺、交易系統等,通過擴展接口傳遞
    用戶身份信息,如數字證書信息、數字簽名信息等,進行二次身份認證,保證單點登陸的安
    全性。
    權限控制:系統采用LDAP 對用戶資源進行統一的管理,同時提供二次開發接口,可以
    與其他應用系統的用戶管理模塊對接,并能隨相關業務系統實時更新訪問權限。通過完善的
    授權機制及存取控制,用戶訪問權限控制到字段級別,確保用戶只能訪問具有權限的應用系
    統及相關信息。
    內容管理: 實現應用系統之間實時交換信息。采用多種緩存機制,保證內容交換的性能
    和準確性。采用基于XML 的Rich Site Summary (RSS)標準,迅速在各應用系統之間傳播最
    新變化。
    信息發布: 實現信息門戶內容的動態維護。動態網站系統可與OA 協同辦公系統、知識
    管理系統等集成,網站信息須經OA 系統的審批流程流轉通過后或知識管理平臺設置具有外
    部共享權限后才可正式發布,真正實現內外信息發布的同步。
    文件管理: 系統實現無縫集成多種數據源,包括:數據庫、文檔(Office 文檔、PDF、
    AutoCAD、甚至ZIP 文檔)、Web 網頁、FTP 站點等,并對數據按業務要求和職務特點加以分
    析整理,通過統一Web 界面主動推送(Push)至用戶的門戶桌面,幫助用戶做出及時、正確的
    決策。
    1.2.2 Portlet 容器
    Portlet 容器提供Portlet 執行的環境,包含很多Portlet 并管理它們的生命周期,保
    存Portlet 的定制信息。
    一個Portal 容器接收到來自Portal 的請求后,接著將這個請求傳遞給存在Portal 容
    器的Portlet 執行。Portlet 容器沒有義務去組合Portlet 產生的信息內容,這個工作必
    須由Portal 來處理。Portal 和 Portal 容器可以放在一起視為同一個系統的組件,或者分
    開成為兩個獨立的組件。
    Portlet 容器是普通Web Servlet 容器的擴展,所以一個Portlet 容器可以構建于一個
    已經存在的Servlet 容器或者可能實現全部Web Servlet 容器的全部功能。無論Portlet
    容器怎么實現,它的運行環境總是假定它支持Servlet2.3 規范。

    通常,Portlet 容器擴展自普通的Servlet 容器。
    第三節 什么是Portlet
    Portlet 是Portal 中最重要的組件,負責在Portal 中呈現信息內容,有相應的生命周
    期。通過自定義Portlet,用戶很容易定義個性化的Portal 頁面。Portlet 由Portlet 容器
    負責管理、處理請求并返回動態頁面,可以作為Portal 的可即插即用的界面組件。
    1.3.1 Portlet
    一個Portlet是以Java技術為技術的Web組件,由Portlet容器所管理,專門處理客戶的
    信息請求以及產生各種動態的信息內容。Portlet 為可插式的客戶界面組件,提供呈現層成
    為一個信息系統。
    這些由Portlet產生的內容也被稱為片段,而片段是具有一些規則的標記( HTML、XHTML、
    WML ),而且可以和其他的片段組合而成一個復雜的文件。一個或多個 Portlet 的內容聚合
    而成為一個 Portal 網頁。而 Portlet 的生命周期是被 Portlet 容器所管理控制的。
    客戶端和Portlet的互動是由Portal通過典型的請求/響應方式實現,正常來說,客戶會
    和Portlet所產生的內容互動,舉例來說,根據下一步的連接或者是確認送出的表單,結果
    Portal將會接收到Portlet的動作,將這個處理狀況轉向到目標Portlet。這些Portlet 內容
    的產生可能會因為不同的使用者而有不同的變化,完全是根據客戶對于這個Portlet的設置。
    1.3.2 Portlet 與Servlet 的關系
    Portlet 被定義成為一個新的組件,具有新的明確的界面與行為。為了盡可能與現有的
    Servlet 結合達到重復使用的目的,Portlet 的規范利用了 Servlet 的規范,許多觀念都
    很相似的,結合 Portlet、Servlet 及 Jsp 在同一個網站系統中,我們稱為Portlet 應用 。
    在同一個 Portlet 應用 中,他們將分享同一個類加載器(ClassLoader),上下文(Context)
    及 Session。
    ①、Portlet 和 Servlet 的相似之處
    @ Portlet 也是 Java 技術的 web 組件
    @ Portlet 也是有特定的 container 在管理
    @ Portlet 可以動態產生各種內容
    @ Portlet 的生命周期由 container 所管理
    @ Portlet 和客戶端的互動是通過 request/response 的機制
    ②、Portlet 和 Servlet 也有一些不同
    8
    @ Portlet 只產生 markup 信息片段,不是完整的網頁文件。而 Portal 會將所有的
    Portlet markup 信息片段放到一個完整的 Portal 網頁。
    @ Portlet 不會和 URL 有直接的關系
    @ 客戶端必須通過 portal 系統才能和 Portlet 互動
    @ Portlet 有一些定義好的 request 處理,action request 以及 render request。
    @ Portlet 默認定義 Portlet modes 及窗口狀態可以指出在網頁中該 Portlet 的哪個功
    能正在執行及現在的 狀態。
    @ Portlet 可以在同一個 portal 網頁之中存在多個。
    ③、Portlet 有一些附加的功能是 Servlet 所沒有的
    @ Portlet 能夠存取及儲存永久配置文件及定制資料。
    @ Portlet 可以存取使用者數據
    @ Portlet 具有 URL 的重寫功能在文件中去動態建立連結,允許 portal server 不用去
    知道如何在網頁的片 段之中建立連結及動作。
    @ Portlet 可以儲存臨時性的數據在 Portlet session 之中,擁有兩個不同的范圍 :
    application-wide scope 及 Portlet private scope 。
    ④、Portlet 不具有一些功能, 但是 Servlet 卻有提供
    @ Servlet 具有設置輸出的文字編碼( character set encoding)方式
    @ Servlet 可以設置 HTTP 輸出的 header
    @ Servlet 才能夠接收客戶對于 portal 發出的 URL 請求
    1.3.3 Portlet 的生命周期
    一個Portlet有著良好的生命周期管理,定義了怎樣裝載,實例化和初始化,怎樣響應來
    自客戶端的請求及怎樣送出服務。這個Portlet生命周期由Portlet接口的init,processAction,
    render和destroy方法來表達。
    載入和實例化:Portlet 容器負責載入和實例化Portlet。當Portlet 容器運行Portlet 應用或
    者延遲到Portlet 需要服務使用者的請求時,Portlet 就會被載入并實例化。載入Portlet 類后,
    Portlet 類隨即被實例化。
    初始化:Portlet 類實例化后,Portlet 容器還需要初始化Portlet。以調用Portlet 去響應客
    戶端的請求。Portlet 容器呼叫Portlet 接口中的init 方法初始化Portlet。擴展自PortletConfig
    的類可以取出定義在部署描述文件中的初始化參數,以及Resource Bundle。
    初始化異常:在 Portlet 初始化期間,Portlet 可能會丟出 UnavailableException 或
    PortletException 異常。此時,Portlet 容器不能把 Portlet 置入已啟動的服務,并且 Portlet
    容器必需釋放這個 Portlet。 destory 方法不能被呼叫,因為初始化被認為執行失敗。發生 失
    敗后,Portlet 容器會嘗試著重新實例化及初始化 Portlet。這個異常處理的規則是:由一個
    UnavailableException 指定一個不能執行的最小時間,當此異常發生時,Portlet 容器必需等
    到指定時間過去后才產生并且初始化一個新的 Portlet。
    在初始化過程中所丟出的 Runtime Exception 異常,被當作 PortletException 來處理。

    posted @ 2007-07-15 20:16 dennis 閱讀(1361) | 評論 (2)編輯 收藏

        Lich Ray寫了個帖子《函數式編程語言曲高和寡?》,用快速排序的例子來說明函數式編程在表達思想方面比命令式語言更容易,其實這一點毋庸置疑,如果你正在讀或者讀過SICP的話。文中給了haskell、scheme和javascript的實現例子,我也湊趣寫了個Erlang版本,haskell我不了解就不說了,其他實現分別如下:
    scheme:
    (define (qsort ls)  
         (
    if (null? ls) '()  
             (let  
                 ((x (car ls))  
                 (xs (cdr ls)))  
                 (let   
                     ((lt (filter (lambda (y) (< y x)) xs))  
                     (st (filter (lambda (y) (>= y x)) xs)))  
                     (append (qsort lt) (list x) (qsort st))))))  

    javascript:
        // 把要用到的表達式抽象出來  
        Array
    .prototype.head = function () {  
            
    return this[0];  
        }  
          
        Array
    .prototype.tail = function () {  
            
    return this.slice(1);  
        }  
          
       Array
    .prototype.filter = function (proc) {  
           var tmpArr 
    = [];  
           
    for (var i = 0; i < this.length; i++)  
           
    if (proc(this[i]) == true)  
               tmpArr
    .push(this[i]);  
           
    return tmpArr;  
       }  
       Array
    .prototype.qsort = function () {  
           
    if (this == false) return []  
            var x
    , xs, lt, st  
           x 
    = this.head()  
            xs 
    = this.tail()  
            lt 
    = xs.filter(function (y) {return y < x})  
            st 
    = xs.filter(function (y) {return y >= x})  
            
    return lt.qsort().concat([x], st.qsort())  
        }  
    用Erlang的話,Erlang的list其實跟scheme的list是一樣的,甚至連定義的基本高階函數都一樣:map,filter,append等等,利用lists模塊提供的filter和append,我們可以寫出:
        qsort([])->[];  
        qsort([H
    |T])->  
            Lt
    =lists:filter(fun(E)->E<H end,T),  
            St
    =lists:filter(fun(E)->E>=H end,T),  
        lists
    :append(qsort(Lt),lists:append([H],qsort(St))).  
        我們來比較下scheme和Erlang版本,兩者最顯著的不同是,scheme使用了條件語句if,而Erlang卻是通過模式匹配來代替條件分支判斷。同樣,在list的分解上面,Erlang也是利用了規則匹配來代替car,cdr函數,從這里可以看出規則匹配在Erlang中的主要作用:分解復雜數據結構以便賦值和條件分支的分派。
        扯遠些可以談到模式匹配是以“like-a”來代替消息分派在傳統命令式語言中嚴格的“is-a”,這也跟現實世界的情況更為符合,現實世界中我們對事物的判斷都是模糊。而這一點,不正是“Duck-Typing”?傳統語言對于對象的類型(type)判斷來源于嚴格確定對象是什么類(class),不是這個類它就沒有相應的方法,而事實上類與類型這兩個概念并不是一致的,對象的類型更應該根據對象能夠做什么來決定。扯遠了,這只是我讀《失蹤的鏈環》得來的感受,如果對模式匹配還有懷疑的話,讓我們回到這個例子的Erlang版本,代碼中我們調用了兩次filter進行全表掃描,以便得到根據H切割的大小兩個部分,這在性能上有不小的影響,那么我們能不能只進行一次全表掃描呢,返回結果是“大小”兩個部分,看看Erlang應該怎么寫:
    sort([]) -> [];
    sort([Pivot|Rest]) ->
       {Smaller, Bigger} = split(Pivot, Rest),
       lists:append(sort(Smaller), [Pivot|sort(Bigger)]).
    split
    (Pivot, L) ->
    split(Pivot, L, [], []).
    split(Pivot, [], Smaller, Bigger) ->
    {Smaller
    ,Bigger};
    split(Pivot, [H|T], Smaller, Bigger) when H < Pivot ->
    split(Pivot, T, [H|Smaller], Bigger);
    split(Pivot, [H|T], Smaller, Bigger) when H >= Pivot ->
    split(Pivot, T, Smaller, [H|Bigger]).

        這幾行代碼充分展現了模式匹配的威力,不過Erlang其實有內置的方法partition用于切割list的,這里只是為了展現模式匹配,因此上面的代碼可以改為:
    sort([]) -> [];
    sort([Pivot|Rest]) ->
    {Smaller
    , Bigger} = lists:partition(fun(E)->E<Pivot end, Rest),
    lists
    :append(sort(Smaller), [Pivot|sort(Bigger)]).

    同樣的代碼改寫為ruby版本:
    def qsort(array)
      arr=array.dup
      
    if arr==[]
        []
      
    else
        x
    =arr.shift
        smaller
    ,bigger=arr.partition{|e| e<=x}
        qsort(smaller)
    +[x]+qsort(bigger)
      end
    end
        ruby與Erlang都有并行賦值,但是ruby不支持模式匹配。請注意ruby并沒有尾遞歸優化,因此上面的代碼在數組比較大的時候會導致棧溢出,想用ruby做函數式編程應該盡量多使用循環和map,filter,collect等輔助高階函數。
        另外一個Erlang與ruby、scheme比較重要的區別是Erlang的變量只能賦值一次(或者說綁定),也就是single assignment。這個特點與Erlang所要滿足的運行場景有緊密關系,當系統發生錯誤時,就可以從原來的值重新啟動任務,而不用擔心由于變量值的變化導致系統恢復困難。




    posted @ 2007-07-15 16:11 dennis 閱讀(3007) | 評論 (0)編輯 收藏

    如何設置一個基本的OpenLDAP Server
    本文出自:http://www.linuxforum.net 作者:吳阿亭 Jephe wu (2001-09-04 15:00:01)

          一. 目的 

          本文旨在介紹如何安裝OpenLDAP并且設置一個公司內部的集中化的郵件地址薄服務器供客
          戶端查詢。 
          基本上,OpenLDAPg還應用在其它許多方面,象集中化的用戶帳號驗證服務器,但郵件地址
          薄查詢是最常用的。 

          二. 安裝 

          從www.openldap.org下載最新的openldap軟件包,按照編譯和安裝的步驟,依次運行:


          #tar cvfz openldap-stable-20010524.tgz 
          #cd openldap-2.0.11 
          #./configure 
          #make depend 
          #make 
          #make test 
          #make install 

          我的操作環境是redhat 6.1,如果沒有遇到任何錯誤,最后默認安裝LDAP后臺程序slapd
          到目錄/usr/local/libexec;配置文件在目錄/usr/local/etc/openldap/ 并且放各種
          OpenLDAP工具
          ldapadd,ldapdelete,ldapmodify,ldapmodrdn,ldappasswd,ldapsearch 在目錄
          /usr/local/bin,運行時數據庫在/usr/local/var/openldap-ldbm 。 


          三. 設置 

          1) 更改配置文件/usr/local/etc/openldap/slapd.conf 
          在include /usr/local/etc/openldap/schema/core.schema這行后面加上下面的行,
          包括所有的方案。 

          include /usr/local/etc/openldap/schema/corba.schema 
          include /usr/local/etc/openldap/schema/cosine.schema 
          include /usr/local/etc/openldap/schema/inetorgperson.schema 
          include /usr/local/etc/openldap/schema/java.schema 
          include /usr/local/etc/openldap/schema/krb5-kdc.schema 
          include /usr/local/etc/openldap/schema/misc.schema 
          include /usr/local/etc/openldap/schema/nadf.schema 
          include /usr/local/etc/openldap/schema/nis.schema 
          include /usr/local/etc/openldap/schema/openldap.schema 

          2) 在文件slapd.conf的"ldbm database definitions"部分更改相應的
          suffix,rootdn行如下 

          database ldbm 
          suffix "o=yourdomain,c=us" 
          rootdn "cn=root,o=yourdomain,c=us" 
          rootpw secret 
          directory /usr/local/var/openldap-ldbm 

          有各種格式你可以用,這里我用的是o=yourdomain,c=us 說明你的公司域名和所在的國
          家或地區 
          rootdn的格式安裝后默認為cn=Manager,這里改為root完全是自己的喜好,這樣符合
          Unix/Linux中root具有最高權限的傳統。 

          3) 現在可以啟動slapd了,運行/usr/local/libexec/slapd 。 

          可以考慮把/usr/local/bin and /usr/local/libexec加到搜索路徑中,即加到
          /etc/profile 
          中的PATH行: 
          PATH="$PATH:/usr/X11R6/bin:/usr/local/bin:/usr/local/libexec" 
          這樣下次登錄后只需鍵入 slapd 。 

          4) 測試ldap server是否正常工作。 
          運行下面的命令檢查是否有相應的輸出。 

          #ldapsearch -x -b 'o=yourdomain,c=us' '(objectclass=*)' 


          5) 編輯.ldif文本文件,用ldapadd添加記錄進入LDAP數據庫。 
          文件內容如下: 

          dn: o=yourdomain,c=us 
          objectclass: dcobject 
          objectclass: organization 
          o: yourdomain 
          dc: yourdomain 

          dn: cn=Jephe Wu,o=yourdomain,c=us 
          objectclass: inetorgperson 
          cn: Jephe Wu 
          sn: Wu 
          mail: jephe_wu@yourdomain.com 


          ......more users...... 

          依次類推,添加每個人的記錄進入該文件中,注意對象類型 inetorgperson 至少必須要
          有cn和sn 
          ,這里我們用cn,sn,mail三項定義,這對我們的郵件地址薄功能來說已經足夠。你還可以
          定義象 
          mobile, homephone,pager......等等。 

          然后用下面的命令添加上面的.ldif文件進入LDAP數據庫 

          #ldapadd -x -D "cn=root,o=yourdomain,c=us" -w secret -f
          "yourldiffilename" 

          注:上面的文件的第一部分"dn: o=yourdomain,c=us"是必須的,否則不能添加數據。 
          用你的公司的域名替換上面的"yourdomain"。 

          6) 設置Outlook Express, 允許用LDAP服務器查詢郵件地址。 

          "工具/帳號/添加--目錄服務",填入你的服務器的IP地址或者主機全稱域名,在下一個屏
          幕中選yes以允許用目錄服務來查詢地址,最后在"目錄服務"欄中選中剛才設置的項目擊
          “屬性/高級",在"搜索庫"中填入 
          "o=yourdomain,c=us" 。 
          Netscape請根據上面的信息設置相應的選項。 

          四. 常見使用問題 

          1) 能啟動slapd 沒有問題,但不能添加數據庫,運行ldapadd添加時出錯 "ldap_bind:
          cannot contact LDAP Server" 。 
          答: 最可能的原因是在/etc/hosts中沒有127.0.0.1 localhost項目。 

          2) 注意查詢順序: 如果在Outlook Express的地址薄中有內容,則檢查地址時地址薄優
          先,如果在本地地址薄中找不到相應記錄,然后再查詢LDAP服務器。 

          3) 用下面的命令確信客戶端與LDAP服務器有通訊,在服務器運行下面的命令,然后在OE中
          測試檢查地址,你將會得到查詢LDAP數據庫的連接過程的輸出。 

          # tcpdump port 389 

    posted @ 2007-07-14 16:08 dennis 閱讀(1614) | 評論 (1)編輯 收藏

        在bea的官網下了10.0的weblogic portal,在redhat上安裝了下,想跑個最簡單的portal例子,部署一次幾乎要20分鐘,受不了,可是2G,P4的機器啊。KDE慢吞吞的響應速度本來就夠郁悶了,加上這個可怕的部署時間,阿門。。。手頭的portal資料先看看,項目的portal準備讓我來接手,得預先準備了。在erlang-china看到說《Programming Erlang》準備找人翻譯并出版了,是個好消息,不過看情況要看到中文版要等明年,我等不及了。

    posted @ 2007-07-13 18:40 dennis 閱讀(250) | 評論 (0)編輯 收藏

    僅列出標題
    共56頁: First 上一頁 36 37 38 39 40 41 42 43 44 下一頁 Last 
    主站蜘蛛池模板: 国产曰批免费视频播放免费s| 亚洲黄黄黄网站在线观看| 亚洲国产区男人本色| 亚洲国产高清在线一区二区三区| 久久综合九色综合97免费下载 | 亚洲依依成人精品| 又粗又硬免费毛片| 69视频在线观看高清免费| 亚洲av无码一区二区三区在线播放 | 最近中文字幕mv免费高清视频7| 高潮毛片无遮挡高清免费| 亚洲精品美女视频| 亚洲精品国产V片在线观看 | 99久久精品日本一区二区免费| 国产成人高清亚洲一区91| 777亚洲精品乱码久久久久久 | 免费在线观看亚洲| 一级毛片免费毛片一级毛片免费| 亚洲AV网一区二区三区 | 国产av无码专区亚洲av桃花庵| 成全影视免费观看大全二| 最近免费中文字幕中文高清| 亚洲中文字幕乱码AV波多JI | 国产99精品一区二区三区免费| 亚洲中文字幕一二三四区苍井空| 亚洲人成网站在线观看播放| 全免费一级毛片在线播放| 91久久精品国产免费一区| 国产久爱免费精品视频| 337p日本欧洲亚洲大胆人人| 亚洲一区二区三区亚瑟| 亚洲AV人无码综合在线观看| 亚洲精品456播放| 国产成人免费福利网站| 国产1024精品视频专区免费| 男女作爱在线播放免费网站| 精品多毛少妇人妻AV免费久久| 羞羞的视频在线免费观看| 亚洲 暴爽 AV人人爽日日碰| 亚洲欧洲日韩综合| 亚洲午夜未满十八勿入|