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

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

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

    posts - 176, comments - 240, trackbacks - 0, articles - 7

        witrix平臺中的tpl模板技術的重點在于標簽定義的設計, 在于如何最大限度的發揮xml格式的表達能力。
        tpl自定義標簽的基本結構如下:
        <Namespace:TagName tpl:tag="realTagName"
            tpl:noborder="${booleanExprInCompileContext}"
            tpl:ignore="${booleanExprInCompileContext}"
            attrName="stringOrExpression" cp:attributeInCompileContext="atringOrExpression"
            OtherNamespace:OtherAttrName="stringOrExpression"
            >
            bodyContent
        </NameSpace:TagName>
        自定義標簽總是處在某一名字空間中, tpl名字空間中的屬性由tpl編譯器負責進行解析并處理, 而cp名字空間中的屬性在編譯期能夠訪問,其他名字空間的屬性被完全忽略, 一般只有decorator會識別這些屬性(例如cache:timeout).所有無名字空間的屬性都相當于是自定義標簽的調用參數,在標簽運行的時候 可以在標簽內部訪問到。
        tpl通過對namespace的使用, 避免了系統屬性, decorator屬性與普通標簽屬性之間的相互干擾, 這與JSF和Tapestry都是不同的。
        tpl:tag屬性指定此標簽在編譯時對應的真實標簽名, 即編譯期會識別RealTagName而不是Namespace:TagName。tpl:noborder為true的時候相當于是直接編譯 bodyContent, 例如用來在編譯期控制是否在界面上使用某種邊框。
        tpl:ignore為true的時候,此標簽將被忽略而不會被編譯。
        bodyContent在編譯期成為tagBody變量, 由自定義標簽自己決定如何處理, 這種方式比FreeMarker的<#nested>機制要靈活和強大的多. 例如在標簽內部我們可以使用<cp:compile src="${tagBody}" /> 這等價于 FreeMarker的<#nested>. 也可以使用
        <cp:compile src="${tagBody.existingChild('header')}" />從bodyContent中取出header子節點. 甚至我們可以對tagBody進行加工之后再進行編譯.

    posted @ 2005-11-22 23:09 canonical 閱讀(1023) | 評論 (0)編輯 收藏

        經濟學的核心概念是合同(contract),多個利益主體(具有不同的價值目標)在交互中達成一致協議。這本質上是個多目標優化的問題。這與物理學的精 神是有著本質區別的。物理學傳統上認為世界是完美的,存在著唯一的真理。根據Lagrange原理,最低能量原理等,物理世界總是在眾多可比的備選結構中 選擇那唯一最優的結果。在經濟學中不存在唯一的價值取向,并不是所有的事物之間都是能夠進行比較并排出座次的。比如,我們大多數人會認為10個老婆餅比一 個老婆餅好,10個蔥油餅比一個蔥油餅好,10個老婆餅加10個蔥油餅比一個老婆餅加一個蔥油餅好,但是10個老婆餅和10個蔥油餅之間如何比較,卻是沒 有確定的結果的。數學上,我們說可以建立偏序(partial order)但無法建立全序。因為多個利益主體對同一事物的評價是不可比的(不同的),因而可以產生交換.交換是一個互惠互利的過程. A交出了部分老婆餅換來了蔥油餅,因為A覺得自己的老婆餅很多,還是蔥油餅更有吸引力一些,而同樣B認為自己的蔥油餅很多,他寧肯再要一些老婆餅. 通過一番討價還價的交互過程,我們可以達到所謂的Pareto有效(optimal): 在最終的優化配置中,沒有人能夠在不使別人受損的情況下使自己得益. 即繼續交換下去,A或B中的一個就會覺得不值得了. 注意到經濟學的這種雙贏性質與軍事學和權謀術也是不同的,權謀講求爭鋒相對, 損人即利己, 進攻是最好的防守等等.
       
        多目標優化,意味著我們在一族矢量中尋找最優的一個,盡管在每個維度上我們都能很容易的作出比較和判斷,但綜合起來卻需要反復的權衡。在凸分析 (Convex Analysis)中標量化(Scalarization)是尋找Pareto有效點的常用方法. 即定義一個價格矢量, 優化時考慮總體價格. 價格的存在意味著市場的存在, 意味著我們在考慮優化問題的時候,可以只考慮自身與市場的交互,而不用考慮眾多其它利益主體的存在(類似于物理中的場方程). 理論上可以證明,在均衡價格處可以實現Pareto最優。


        說了這么多經濟學,它和軟件有什么關系呢。稍微留意一下就會發現,現在軟件中越來越強調合同和涉眾(stakeholder)利益了(參考use case)。早期,面向過程編程時,系統的目標比較單一:滿足當前系統功能需求。基本上系統中的每一個函數在編寫的時候都服從于一個目標,即當前系統的運 行。在編制的時候多半都想著向著最終的目標邁進,系統的各個部分之間是精確(detailed)匹配的。(想想VB的代碼吧)。采用面向對象的思想方法之 后,系統中出現了多個利益的實體,它們定義并保護著自身的利益。系統的目標不再是完成功能,而是實現用戶價值,穩定運行,便于維護等多重價值目標。在面向 對象以后,我們經常會發現,最終我們實現的功能點會多于面向過程開發的時候。很多對象函數在當前系統中最終并沒有調用,但考慮到重用性和完備性等,我們還 是編寫了相應的代碼。很多商用組件對象的功能集更是大得驚人,我們永遠只是用到其中的一小部分。系統的架構便是由對象之間相互協作并相互競爭支撐起來的.   在面向對象設計中, 我們說對象對外暴露的接口是與外部世界達成的contract, 而接口函數則反映了一次交互過程.有時我們采用如下方法, 讓調用雙方都能平等的獲得處理機會.
    class A{
       void someFunc(B b){
          b.someFunc();
       }
    }

        XP敏捷編程強調快速迭代, 但絕不意味著不進行架構設計. 按照級列設計理論, 復雜性是分級的, 我們要采用滿足當前需求的最簡單的設計,而不是絕對意義上的最簡單的設計. 而且簡單與完備性還是兩回事,雖然簡單,但是功能仍然要是完備的. 這是個架構性問題. 迭代是個逐步精化的過程,而很少是格式塔式的革命. 在XP中我們應該更加強調architecture centric.
        重構是不影響系統外部特征的情況下,對系統內部結構的修改. 但我們現在要從結構A走向結構B,重構的路徑到底在哪里。推翻了重新寫并不是重構。雖然XP強調當前,不要過多考慮未來,但這只是個重點問題,并不意味著 不考慮未來,我們需要為復雜性的方向性發展保留出一定的通道。實際上重構的過程中,架構本身對應的概念是基本不變的,只是結構在調整,在細化。如果你大腦 癡呆,先天遺傳不利,無論怎么重構知識結構大概也難以避免被淘汰的命運. 重構也會陷入Pareto最優點,因為一些對象作為即得利益者,讓它放棄自己的功能集并不是那么容易的事情。它會爭辯說,我和XX建立了關聯,基于我的 YY功能,ZZ已經作了大量開發而且已經發布出去。。。

        目前軟件設計中沒有"市場"的概念, 在權衡系統功能歸屬的時候,我們只能兩兩進行: 這個功能放在對象A里好呢還是放在B里好呢. 是一個相當費力的過程.
       
        最后,再為物理學說句話。表面上看起來,物理學是由最優化原理支配的,但它還要受到所謂對稱性的制約。很多時候當我們面臨兩難選擇的時候,對稱性會幫助我 們作出選擇。對稱性(根據Nother定理,守恒律也是對稱性的一種)維護了物理學內部的結構張力。

    posted @ 2005-11-22 17:59 canonical 閱讀(663) | 評論 (2)編輯 收藏

        過程控制的要點是哪些?我從以下幾點來考慮這個問題。
     第一點是測量,衍生出定義,標識,記錄,評判等。測量需要在具有分歧的變化之處進行(與其它過程的交連之處)。
      第二點是預測,預測不準的原因一般是信息不足或者是非線性。確定性系統中可以產生貌似隨機的混沌現象。物理學中混沌控制的基本要點是縮短控制間隔,盡量利 用確定性的信息,而且間隔減小之后,多半可以部分恢復線性。此外,控制所需的信息也并不需要是整個動力學過程的全部信息,只需要是某個動力學切面上的信息 即可。

     第三點是控制點的選擇,控制點分為時點(時機)和位點(對象)。有時需要在系統中制造出某個瓶頸來便于施加控制。

     第四點是執行,控制的基本策略分為負反饋和正反饋,這就需要信息的傳遞(交流)。正反饋策略在非線性系統控制中其實非常重要(飽和)。

     第五點是協調(組織),控制的整體結構具有周期結構(節奏),網狀結構(交互),層次結構(抽象)等。

     第六點是變化,有序的動態結構變化稱為演化(持續改進),而演化最重要的是方向,或者說是目標,或者說是價值。

     第七點是學習,改進是學習特別是從錯誤中學習的結果。傳統制造業的控制因為流程非常固化,其實并不注重學習。

     越來越復雜的系統最終只有一個詞能夠描述:生態。

    posted @ 2005-11-22 17:58 canonical 閱讀(312) | 評論 (0)編輯 收藏

    quartz是一個高質量的任務調度軟件包。其主要組成部分為:

    Scheduler接口: quartz的執行線程,它根據Trigger決定調度時刻,根據JobDetail的說明實例化并運行Job

    JobDetail類: 可持久化的任務描述信息。任務雖然分組,但是僅用作管理標示,任務之間并無實質性關聯, 例如無法定義job chain。

    Trigger類:任務的調度策略。這里的特點是調度策略與任務描述分開,調度策略和任務描述都可以分別在Scheduler注冊,然后再關聯起來。JobDetail與Trigger的關系是一對多。

    JobDataMap: 將任務的運行時可持久化狀態信息從JobDetail類中分離出來

    Job接口: 任務的執行代碼

    StatefulJob接口: 無狀態任務對應的JobDataMap可以認為是只讀的,而有狀態的任務在多次執行過程中保留對JobDataMap所作的修改,一個后果是有狀態任務無法被并發執行。

    JobExecutionException類: 可以通過JobExecutionException調整調度程序的下一步動作
    Calendar接口: 用于從trigger的調度計劃中排除某些時間段,例如假期等。

    以上幾個部分的交互關系如下:
    class JobImpl implements Job{
        public void execute(JobExecutionContext context) throws JobExecutionException{
            JobDetail detail = context.getJobDetail();
            JobDataMap dataMap = detail.getJobDataMap();
            ...
        }
    }

    scheduler.addCalendar("myHolidays", holidayCalendar, false);
    trigger.setCanlendarName("myHolidays");

    JobDetail jobDetail = new JobDetail(jobName, jobGroupName, JobImpl.class);

    scheduler.scheduleJob(jobDetail, trigger);

    JobDetail可以設置如下屬性:
    1. Durability: non-durable的任務當不再與任何active trigger關聯的時候將會從scheduler中被自動刪除。
    2. Volatility: volatile的任務在scheduler的兩次啟動之間不會被持久化
    3. RequestsRecovery: 如果在執行過程中程序意外崩潰,標記為"request recovery"的任務在scheduler重起之后將會被再次執行,此時JobExecutionContext.isRecovering()返回true.

    Trigger可以設置如下屬性:
    1. misfireInstruction: 設定當trigger錯過了觸發時刻的時候需要采取的處理策略

    SimpleTrigger按照固定的時間間隔進行觸發
    startTime, endTime, repeatCount, repeatInterval

    CronTrigger按照日歷間隔進行觸發
    seconds minutes hours day-of-month month day-of-week

    在quartz內部,QuartzSchedulerThread按照時間順序選擇trigger(沒有任務優先級的概念), 然后在JobRunShell中運行Job。

    JobRunShell中的調用順序如下:

    TriggerListener.triggerFired
        Called by the Scheduler when a Trigger has fired, and it's associated JobDetail is about to be executed.

    TriggerListener.vetoJobExecution
        Called by the Scheduler when a Trigger has fired, and it's associated JobDetail is about to be executed.

    JobListener.jobToBeExecuted
        Called by the Scheduler when a JobDetail is about to be executed (an associated Trigger has occured).

    Job.execute
        Called by the Scheduler when a Trigger fires that is associated with the Job.
     
    JobListener.jobWasExecuted
        Called by the Scheduler after a JobDetail has been executed, and be for the associated Trigger's triggered(xx) method has

    been called.

    Trigger.executionComplete
        Called after the Scheduler has executed the JobDetail associated with the Trigger in order to get the final instruction

    code from the trigger.

    TriggerListener.triggerComplete
         Called by the Scheduler when a Trigger has fired, it's associated JobDetail has been executed, and it's triggered(xx)

    method has been called.

    SchedulerListener.triggerFinalized [if(trigger.getNextFireTime() == null)]
         Called by the Scheduler when a Trigger has reached the condition in which it will never fire again.

    posted @ 2005-11-22 17:55 canonical 閱讀(1101) | 評論 (0)編輯 收藏

      hibernate等O/R Mapping軟件包中使用javabean來作為數據的載體, 但這些bean一般除了get/set等數據訪問方法之外沒有什么其它的業務方法。 前一段時間有人認為這是所謂貧血的領域模型(Anemia Domain Model),引發了一場討論。 其實這些bean的作用僅是表達了領域內的數據關系, 本身并不可能作為完整的領域模型層存在。 在數據層,我們所需要的是數據對外暴露,因為我們無法預知這些數據的使用方式, 就象是實驗數據發表出來以后你無法預知別人如何分析一樣,這時信息流是開放的,向外的:信息在這里,放馬過來吧。 而在業務邏輯層,復雜的邏輯控制交織在一起,我們需要精細的控制信息通道,通過函數封裝,我們反轉了信息流的方向:取到什么數據是由調用者提供的信息決定 的。
         實際上,在ORM軟件中使用的bean基本上與一個Map類似,只是它具有java Class所提供的元數據,而訪問數據時又必須通過get/set方法,因而在這些方法中能夠根據元數據動態的作出響應。在witrix平臺的統一數據訪 問框架中主要基于Map等通用數據類型,而不是個性化的bean。為了使得Map具有與bean一樣的動態響應能力,只需要加入meta的支持即可。
    interface IExMap extends Map{
         IMapChecker getChecker();
      Map getModifications();
      ...
    }
    在get/set之前可以通過IMapChecker來實現動態處理,對Map中數據所作的修改也可以記錄下來

    posted @ 2005-11-22 17:53 canonical 閱讀(308) | 評論 (0)編輯 收藏

        在程序中需要返回一個數據集合的時候, 應該盡量選用標準的Java集合類接口,例如List, Map等. 有時也見到有人選擇返回Iterator對象, 一般情況下這不是很好的選擇. Iterator對象的功能有限, 而且存在一種即時消費的特點, 我們一般不能把一個Iterator保存起來留待以后使用. 而且JDK提供的集合類也不能從Iterator直接構造出來,例如沒有 new ArrayList(myIterator), 這樣為數據復制造成一定的困難.
        Iterator在理論上的好處之一是可以支持延遲加載數據, 但是實現起來比較繁瑣而且單條加載也是比較低效的. 在witrix平臺中如果需要延遲加載數據集合, 我一般選擇使用IPageViewer接口
           interface IPageViewer{
               public List getAll();
               public int getTotalCount();
               public List listPage(int startPos, int maxCount);
           }
        IPageViewer通過getAll()可以轉換到List, 也可以通過 new Pager(pageViewer,pageSize).itemIterator()得到單條數據的Iterator, 其內部采用分頁加載模式. 搜索引擎返回的結果和數據庫查詢的結果都可以使用這一接口.

    posted @ 2005-11-19 11:04 canonical 閱讀(332) | 評論 (0)編輯 收藏

     Ivar Jacobson 在其著作"Aspect-Oriented Software Development with Use Cases"中將AOP(Aspect-Oriented Programming)上升為一種貫穿軟件開發全生命周期的設計技術,由建筑學的隱喻引出了decoration overlay(existion + extensions)的策略。在建筑學中,首先基礎設計圖規劃了房間的空間劃分,電氣工程師基于這張基礎圖決定電氣設施排布圖,而裝修設計師可能依據基 礎設計圖決定裝修方案。所有這些擴展(extension)設計圖疊加到基礎設計圖之上構成的最終設計方案決定了房間每個部分的最終功能。這也有些象是中 國傳統彩畫的印制技術:每次印刷一種顏色,多重疊加之后構成成品。
     Jacobson指出傳統的面向對象設計將會產生兩個問題: tangling和scattering。tangling指的是一個組件要參與多個業務, 因而組件具有的功能是所有業務所需功能的超集, 雖然很多功能只在某一項特殊業務中使用,并無重用需求, 但組件開發者在設計和開發時卻無法局域化, 必須同時理解所有需求。 scattering指的是某一特定需求可能需要多個組件協同操作來完成, 這要求實現代碼分散在多個組件之中,而沒有一個整體概念。這兩個問題的產生是因為缺乏一種全局的separation of concern。AOSD(Aspect-Oriented Software Development)正是Jacobson指出的解決方案。
     AOP 在基本的技術含義上可以認為是實現了基本動作與修飾語之間的正交分解,Jacobson將其擴大化為基礎架構(architecture)與擴展 (extension)之間的正交分解,將architecture centric設計與use case, AOP等概念聯系起來。 Jacobson指出程序中在兩個不同的層面上存在著獨立的正交分解結構,一個是組件結構(具體化為Class),一個是業務邏輯結構(具體化為use case)。The element structure identifies where elements of the system are located in the element namespace. It structures the elements hierarchically in terms of layers, packages, classes, and the features within these classes. The use case structure defines how you overlay functionality onto the element structure. 因為use case需要多個組件的參與,當我們將use case結構疊加到組件結構之上時就會產生tangling和scattering。Jacobson指出每一個use case是一個功能切片(slice), 并為use case中的概念找到了相應的程序對應物,因而可以在后期通過AOP技術將use case slice織入到系統基礎架構中,從而構成一種全程建模技術。use case中的generalization可以對應于對象繼承, 包含(include)可以對應于對象組合和調用, 而擴展(entension)就對應于AOP。某些use case具有共性,如常見的CURD(Create,Update,Read, Delete)操作,可以被抽象為參數化的use case, 這可以對應于模板(template)概念。
     我在數年前也注意到了tangling現象,一些類的功能不斷膨脹而完備性卻始終無法保證。在概念 上我們可以將功能集正交分解為不同的接口,但實現時卻需要集中實現,因為它們對應于同一個對象實體。當時我主要通過interface的 aggregation來解決這個問題,例如采用IDynamicInterfaceSupport接口,動態注入接口實現.
         interface IDynamicInterfaceSupport{
          Object queryInterface(Class interfaceClass, Object user);
       void addInterface(Class inf, Object impl);
      }
      使用接口來處理這些問題很多時候效果并不好。首先接口要求預先有一個明確的定義,要求明確標注出功能的獨特性,這樣在合成的時候具有一定的困難。例如在C ++中我們將對象如果分解為大量的接口,則使用的時候需要不斷的queryInterface,十分麻煩。只有弱化種類型區別,才能消除這種合成障礙。例 如在腳本語言中,我們可以自由的使用對象的所有函數,而不需要知道它是哪個接口具體提供的。我在C++中主要通過代碼生成技術構造一個合成代理對象來解決 這個問題,在java中主要使用interface的extends。接口意味著某個明確的定義,而模板(template)在這方面的要求則弱得多,模 板只要求對象具有需要的函數,有時可以做到更好的可重用性。接口的另一個困難在于無法捕獲cross-cutting concern。在沒有AOP的代碼注入技術之前我們主要是通過繼承來構造擴展點,這些都是所謂侵入性(intrusive)的設計,要求不必要的附加層 次,而且具有很強的事前假定。
      在jsplet中WebObject的注冊格式可以認為是實現了action slice。WebObject具有的全部功能可以通過多個action集合組裝出來,而這多個action slice共享一個對象名和成員變量空間。
     <type name="Demo">
      <!-- 如果未指定object, 則缺省為WebObject類型 -->
      <object class="demo.MyWebObject" />
      <listener>
       <url-listener url="/demo/ActionSliceA.jsp" />
       <url-listener url="/demo/ActionSliceB.jsp" />
      </listener>
     </type>
           在tpl模板中,因為xml格式定義了明確的結構信息,所以我們比較容易的定義擴展點,并注入新的功能,例如<c:decorator>標簽。這也類似于AOP的操作。

    posted @ 2005-11-19 11:03 canonical 閱讀(734) | 評論 (1)編輯 收藏

    交叉表(Cross Table)的基本特點是具有橫縱兩個自由延展的維度,而平面表結構只有一個可延展的維度,因為平面表的列名和列數是確定的。例如,地區的產品銷售數量,在平面表中表達為
    district_id product_id sell_num
    如果表現為交叉表,則為
               productA  productB
    districtA   sellNum   sellNum
    districtB   sellNum   sellNum
    這種結構上的失配需要通過程序邏輯來進行調整。

    注意到平面表結構只具有一個可延展的維度,而join可以看作是該維度上的連接操作。因此我們可以將交叉表看作是多個簡單平面表結構并置的結果。即分解為
    A:        
               productA
    districtA   sellNum
    districtB   sellNum

    B:
               productB
    districtA   sellNum
    districtB   sellNum

    橫向維度的擴展在程序中表達。

    SqlInfo結構封裝了這種簡單平面表的分解片斷。
    class SqlInfo{
        List fieldNames;
        SQL sql;
        String keyField;
    }

    我們在程序中通過JoinBuilder來實現橫向維度的構造
    JoinBuilder.begin(sqlInfoA)
               .join(sqlInfB)
               .leftJoin(sqlInfoC)
               .end();
    生成的sql語句示例如下
    select sqlInfoA.fieldNames, sqlInfoB.fieldNames
    from sqlInfoA.sql join sqlInfoB.sql
    on sqlInfoA.keyField = sqlInfoB.keyField

    posted @ 2005-11-19 11:02 canonical 閱讀(310) | 評論 (0)編輯 收藏

    數據導出的功能大致可以分解為三個部分: 1. 從數據源讀取一條記錄 2. 將一條記錄導出為指定格式 3. 循環調用1和2
    首 先我們需要一種機制來對外暴露數據源(一種Container)中的數據,Iterator模式恰能滿足要求。其次,我們需要一種機制來對一系列數據進行 處理,這對應于Visitor模式。第三,在組合Iterator模式和Visitor模式的處理過程中,我們需要表達出平面表數據集的基本特征。
    在witrix平臺中,平面表數據導出和轉換通過TablePageProcessor對象來完成,
    class TablePageProcessor{
     IPageViewer viewer;

     public Object process(ITableVisitor visitor){
      Pager pager = new Pager(viewer, pageSize);
      Iterator it = pager.itemIterator();
      visitor.visitBegin(headers);
      while(it.hasNext()){
       Object row = it.next();
       if(!visitor.visitRow(row))
        break;
      }
      return visitor.visitEnd();
     }
    }

    interface ITableVisitor{
     void visitBegin(List headers);
     boolean visitRow(Object row);
     Object visitEnd();
    }

    IPageViewer是暴露平面表數據的標準接口,它通過Pager對象的包裝之后可以提供各種Iterator.
    ITableVisitor體現了平面表數據的基本特征: header + 一系列row, 存在數據邊界(起始與終止)
    TablePageProcessor固化了IPageViewer和ITableVisitor的組合過程。
    ITableVisitor可以有多種實現,例如CSVBuilder, ExcelBuilder等等。

    posted @ 2005-11-19 11:01 canonical 閱讀(345) | 評論 (0)編輯 收藏

    分頁的功能由兩部分組成:取數據和計算分頁。其中取數據的功能由IPageViewer接口實現
    interface IPageViewer{
     int getTotalCount();
     List getAll();
     int listPage(int startPos, int maxCount);
    }
    Pager是用戶調用時的接口
    class Pager{
     public List getAll(){}
     public List listPage(){}
     public int getPageCount(){}
     public int getPageSize(){}
     public int getCurrentPage(){}
     ...
    }
    Pager使用IPageViewer作為數據供體,自身僅提供分頁計算的功能。在witrix平臺中, IPageViewer是表格數據的標準列舉方式,因為與List接口相比,IPageViewer容許部分加載。
    IPageViewer 可以有多種實現,如ListPageViewer, XmlPageViewer, ExcelPageViewer, DbTablePageViewer等。一般情況下Pager提供的功能已經足夠了,特殊情況下可以通過繼承來擴展。例如卡片瀏覽和分頁瀏覽模式之間的互 相切換通過派生類ItemPager來實現。

    posted @ 2005-11-19 11:00 canonical 閱讀(259) | 評論 (0)編輯 收藏

    僅列出標題
    共18頁: First 上一頁 10 11 12 13 14 15 16 17 18 下一頁 
    主站蜘蛛池模板: 亚洲avav天堂av在线网毛片| 亚洲精品综合在线影院| 又黄又大的激情视频在线观看免费视频社区在线 | 日本在线高清免费爱做网站| 色拍自拍亚洲综合图区| 三年片在线观看免费观看大全一| 亚洲av无码国产精品色午夜字幕| 18禁超污无遮挡无码免费网站| 亚洲成色WWW久久网站| 成人爽a毛片免费| 亚洲综合日韩中文字幕v在线| 中文字幕视频免费| 亚洲二区在线视频| 好爽又高潮了毛片免费下载| 日韩色日韩视频亚洲网站| 免费人成视频在线观看视频 | 久久国产亚洲精品无码| 69av免费观看| 亚洲色大成网站www永久网站| 国产无遮挡又黄又爽免费视频| 又黄又大的激情视频在线观看免费视频社区在线 | 久久夜色精品国产亚洲av | 乱爱性全过程免费视频| 日韩一卡2卡3卡4卡新区亚洲| 你是我的城池营垒免费看 | 亚洲网站免费观看| 成年女人免费v片| 色吊丝性永久免费看码| 久久精品亚洲视频| 成年人网站在线免费观看| 免费国产高清毛不卡片基地| 亚洲国产精品高清久久久| 午夜宅男在线永久免费观看网| 亚洲av日韩av永久无码电影| 亚洲精品tv久久久久久久久 | 丰满人妻一区二区三区免费视频| 蜜芽亚洲av无码精品色午夜| 日本高清免费网站| 最近免费mv在线观看动漫| 亚洲精品国产综合久久久久紧| 伊人久久大香线蕉亚洲五月天 |