亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

BPEL為何不是BPM的圣杯?

系統(tǒng) 1600 0

BPEL為何不是BPM的圣杯?

作者 Pierre Vigneras 譯者 胡鍵 發(fā)布于 2008年12月26日 上午2時32分

介紹

看看最新的文章和各類 BPM 解決方案,很容易讓人假定 BPEL 是實現(xiàn)工作流引擎時所使用的事實標準。從技術角度看,這可能相當正確,但極少有人會說BPEL能很容易地被終端用戶(即業(yè)務分析師)理解。在實踐中,他們無疑會首先選擇以符號(如 BPMN )為基礎的圖形化工具。本文將幫助讀者理解技術觀點(BPEL贊成派)和分析師觀點(BPMN贊成派)的差異。進而,本文將解釋以BPEL為基礎的BPM 解決方案為何不是BPM問題解決方案的大勢所趨,即使它們都能消除這種差異(因為它們通常都提供了BPMN到BPEL的映射)。我們將使用一個現(xiàn)實世界的例子來闡述我們的論點。

編程語言中的并行和結構化

是一門結構化語言,原因是它是基于“塊(Block)”的,這一點與諸如Java和C等這些傳統(tǒng)語言非常類似。這一特性部分源于它的前身:Microsoft的XLANG,它也是基于“塊(Block)”的。然而,BPEL的血統(tǒng)還包含了IBM的WSFL,而它對于我們的后續(xù)討論非常重要,因為它基于圖形的(因此是非結構化的)。這樣我們就發(fā)現(xiàn):BPEL是一個結構化(塊[Block])和非結構化(控制鏈和事件)的混合體。而正是后者給結構化的世界引入了一絲非結構化的氣息……因而結論是,BPEL不是一門結構化語言,就算它看起來像也無法改變這一事實。

相反,BPMN是一種天生就具有非結構化特性的流程圖符號。不要對此表示懷疑。在BPMN規(guī)范 [BPMN06] 的11章(137頁)中,它提供了一個從BPMN到BPEL的直接映射。一些BPMN編寫者(和用戶)認為BPMN是一個以BPEL語言為基礎的簡單GUI。這并不十分正確,在 BPMN FAQ 中這樣解釋道:

“BPEL能夠描述的流程拓撲設計時就存在局限,用BPMN可以表達的流程有可能無法映射到BPEL。”

本文將對于這句重要陳述給出一些根本細節(jié)。但在此之前先讓我們先關注一下結構化和非結構化語言對比。為什么這非常重要?主要原因在于,對非結構化語言進行代碼分析要遠遠難于結構化語言(如Java、C,以及其他——就算不是全部——廣為使用的編程語言)。代碼分析的應用范圍很廣,從錯誤檢查(比如編譯器),到Bug檢測(如findbugs、死鎖檢測……)以及質量檢查(如checkstyle)。

B?hm和Jacopini的一條重要法則 [BOHM66] (并在 Wikipedia上有通俗的解釋 )認為:編程語言只消以3種方式組合子程序,它就能實現(xiàn)任何可計算功能。這三種控制結構是:

  • 先執(zhí)行子程序1,然后執(zhí)行子程序2(順序);
  • 根據(jù)布爾變量的值執(zhí)行兩個子程序中的一個(選擇);
  • 執(zhí)行一個子程序,直到布爾變量的值為真(循環(huán))。

這基本意味著任何(非結構化的)流程圖都能夠轉化成一個結構化的內容。這形成了Dijkstra的論文《Go To語句是有害的》 [DIJKSTRA68] 的基礎。

盡管仍然還有關于“我們是否應該允許非結構化編程語言的存在”的爭論,但事實是:

  1. 世界上大多數(shù)的學生都被灌輸了結構化語言;

  2. 使用最廣泛的編程語言是(非嚴格的)結構化編程語言;

  3. 大多數(shù)非結構化編程語言已經(jīng)引入了一些結構化單元(BASIC,COBOL,F(xiàn)ORTRAN)。

因此一般而言,大多數(shù)程序員確實會關注結構化編程,但是有時出于各種原因(主要是可讀性、維護,有時是性能)會使用非結構化語句(goto、jump、break、exceptions)。

業(yè)務分析師書寫的并行和非結構化流程

業(yè)務分析師(BPM的終端用戶)必須處理現(xiàn)實世界 1 發(fā)生的事情,它不僅是非結構化的,而且是高度并行的。這包含兩層含義:

  1. BPM的終端用戶通常都不是計算機工程師,也不是計算機科學家:他們使用為他們準備的流程圖符號(這是最自然的)設計業(yè)務流程,因此是非結構化的(并且是并行的,這才是重點);
  2. 面對并行,非結構化比結構化更具有表現(xiàn)力。

第2點很重要的,它已被Kiepuszewski等人 [KIEPUSZEWSKI00] 正式證明了。事實上,存在有并行非結構化的工作流不能夠被表示成并行結構化的工作流的情況。而且,這種例子非常容易找到。看看下面這個使用BPMN符號的例子(用Intalio BPMN設計器創(chuàng)建):

BPEL為何不是BPM的圣杯?

在一個使用BPEL作為它底層格式的工具中,為了驗證這個圖,需要創(chuàng)建一個單獨的池。我們隨后會討論這個問題,但現(xiàn)在請重點關注名叫 “Employer”的池及其包含的6個活動。只要一名新員工加入公司,一條工作流就會被啟動。首先需要在人力資源數(shù)據(jù)庫中創(chuàng)建一條記錄。同時,必須提供一個辦公室。一旦人力資源活動完成,員工就得接受醫(yī)療檢查。在此期間,會提供給他一臺計算機。而這只能出現(xiàn)在:辦公室已經(jīng)安排好且賬戶已在來自人力資源數(shù)據(jù)庫的信息系統(tǒng)中創(chuàng)建好的情況下。在計算機已提供且醫(yī)療檢查已結束的情況下,員工就可以開始工作了。當然,你可能希望用不同的方式建模這條簡單流程,但是有一點我需要在這里指出,你無法創(chuàng)建一個等同于 2 本流程的一個結構化并行工作流,我的意思是,你永遠也辦不到!我們都將使用這個簡單的例子貫穿全文。

從這個學習中,我們得出第一個結論:

  • 開發(fā)者會很自然地使用順序的結構化單元(塊[Block])編寫他們的程序;
  • BPM用戶會很自然地使用非結構化、并行的單元(圖形)設計他們的流程;
  • 非結構化、并行的工作流比結構化、并行的工作流更具有表達力。

BPM用戶會設計出一些你無法用結構化的并行工作流表達的工作流。更糟的是,它也出現(xiàn)在了 [KIEPUSZEWSKI00] 中,作者表示:就算并行、非結構化工作流能夠轉換成并行、結構化工作流,但這需要額外的變化和(或)節(jié)點,以至于最終結果會導致對終端用戶來說幾乎無法讀懂。我們很快會討論這個可讀性的問題。

BPMN到BPEL的轉換

在文章 [OUYANG06] 中,作者提出了從BPMN到(可讀的)BPEL的自動化轉換。由于規(guī)范中的一些不清晰語義,他們定義了一個BPMN的子集。因此,他們在文中沒有考慮OR 網(wǎng)關(OR Gateway)和錯誤中繼事件(Intermediate Events)。在待設計流程包含多個結束事件(End Event)的情況下,問題就來了。因為轉換工具沒有考慮它們,而把多個結束事件(End Event)工作流轉換成單結束事件(End Event)工作流的標準方法就是使用OR網(wǎng)關(OR Gateway)。算法大致如下:

  1. 盡量找出圖中可以直接映射到BPEL的已知模式(sequence、flow、pick、while……)。對于找到的每個模式,使用包含映射后BPEL代碼的簡單任務來代替這些組件。
  2. 接著,盡量找到一些“準結構化”組件,采用大多數(shù)組件直接映射成BPEL結構的方法,對它們進行轉換。
  3. 接著,搜索非循環(huán)BPMN子模塊(僅僅包含順序流[sequence flow]和并行網(wǎng)關[parallel gateway])。對于它們,使用BPEL控制連接(control link)。
  4. 最后,剩下的部分使用BPEL事件。

其結果就是一個“盡量可讀的”等價BPEL流程。注意,我們總是可以使用BPEL中的事件來將BPMN轉換成BPEL。問題是,其生成代碼根本就不可讀。因而,結論是將任何BPMN圖轉換成一個等價 3 BPEL流程的算法確實存在,只是結果是“盡量可讀的” 4

Intalio的用例

注意,下例中所表現(xiàn)的肯定不是Intalio BPM v2.0解決方案在BPMN到BPEL轉換時使用的算法,如下的簡單例子說明了這一點。以前面的非結構化BPMN圖來說,Intalio的解決方案會將它轉換成 BPEL流程 ,部分顯示如下:

    <?xml version="1.0" encoding="UTF-8"?>
    
<bpel:process
xmlns:bpel="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:vprop="http://docs.oasis-open.org/wsbpel/2.0/varprop"
xmlns:pnlk="http://docs.oasis-open.org/wsbpel/2.0/plnktype"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:this="http://example.com/Unstructured/Employer"
xmlns:Employee="http://example.com/Unstructured/Employee"
xmlns:diag="http://example.com/Unstructured"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:bpmn="http://www.intalio.com/bpms"
xmlns:atomic="http://ode.apache.org/atomicScope"
queryLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0"
expressionLanguage="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0"
bpmn:label="Employer" bpmn:id="_TGthsJkdEd29aqy0ek4Sxw" name="Employer"
targetNamespace="http://example.com/Unstructured/Employer">
<bpel:import namespace="http://example.com/Unstructured"
location="Unstructured.wsdl"
importType="http://schemas.xmlsoap.org/wsdl/" />
<bpel:import namespace="http://example.com/Unstructured/Employer"
location="Unstructured-Employer.wsdl"
importType="http://schemas.xmlsoap.org/wsdl/" />
<bpel:partnerLinks>
<bpel:partnerLink name="employeeAndEmployerPlkVar"
partnerLinkType="diag:EmployeeAndEmployer"
myRole="Employer_for_Employee" />
</bpel:partnerLinks>
<bpel:variables>
<bpel:variable name="thisEmployee_ArrivalRequestMsg"
messageType="this:Employee_ArrivalRequest" />
</bpel:variables>
<bpel:sequence>
<bpel:receive partnerLink="employeeAndEmployerPlkVar"
portType="this:ForEmployee" operation="Employee_Arrival"
variable="thisEmployee_ArrivalRequestMsg" createInstance="yes"
bpmn:label="Employee Arrival" bpmn:id="_THp84JkdEd29aqy0ek4Sxw">
</bpel:receive>
<bpel:flow bpmn:label="GatewayParallel"
bpmn:id="_DHLtcJkeEd29aqy0ek4Sxw">
<bpel:sequence>
<bpel:empty bpmn:label="Fill HR DB"
bpmn:id="_hCvXsJkdEd29aqy0ek4Sxw" />
<bpel:flow bpmn:label="GatewayParallel"
bpmn:id="_H2UWEJkeEd29aqy0ek4Sxw">
<bpel:sequence>
<bpel:empty bpmn:label="Medical Check"
bpmn:id="_ivks8JkdEd29aqy0ek4Sxw" />
</bpel:sequence>
<bpel:sequence>
<bpel:empty bpmn:label="Provide Computer"
bpmn:id="_lXApQJkdEd29aqy0ek4Sxw" />
</bpel:sequence>
</bpel:flow>
</bpel:sequence>
<bpel:sequence>
<bpel:empty bpmn:label="Provide Office"
bpmn:id="_iHEigJkdEd29aqy0ek4Sxw" />
<bpel:empty bpmn:label="Provide Computer"
bpmn:id="_lXApQJkdEd29aqy0ek4Sxw" />
</bpel:sequence>
</bpel:flow>
<bpel:empty bpmn:label="Ready to work"
bpmn:id="_nh6akJkdEd29aqy0ek4Sxw" />
</bpel:sequence>
</bpel:process>

要想將轉換結果顯示成一張漂亮的圖,我們可以在Eclipse BPEL設計器中打開這個流程:

BPEL為何不是BPM的圣杯?

由于某些原因,“Fill HR Db”、“Medical Check”等活動的標簽丟失了,但是無論怎樣,我們都能夠從BPEL的源代碼中看到BPMN的“Employee Arrival”活動已轉成了BPEL的“Receive”操作。對于業(yè)務分析師而言,會對現(xiàn)在看到7個活動(“Receive”和其他6個 “Empty”活動)感到奇怪,而在我們的原始流程中只包含了6個。看看BPEL源代碼就能打消這個疑惑了:我們可以看到“Provide Computer”活動被復制了。在某些方面,這對于員工來說倒是件好事:他們可以在辦公室擁有兩臺計算機!

Intalio BPMN2BPEL轉換算法能否產(chǎn)生可讀的BPEL,并不是這里的問題:問題在于這個轉換完全錯了。你無法想象出,那些專注于現(xiàn)實世界業(yè)務流程的職業(yè)BPM設計者能畫出什么樣的圖,因為這些流程本質上就是高度并行和非結構化的。

可讀性問題

[AALST_UNKNOWNDATE] 中的作者認為:BPEL對終端用戶來說是不可讀的,因此需要一種用于流程設計的高級語言。但一般情況是,在流程真正執(zhí)行之前,就需要運行時信息了。如何把這個信息融入到最終的BPEL代碼中呢?有人可能會認為,這就是生成可讀的BPEL代碼之所以重要的原因。在所有信息直接輸入到編輯器/設計器中的情況下,至少出于調試的目的,BPEL代碼也應該盡量可讀,其中可讀的含義:盡量直接使用BPEL結構(sequence、flow、pick、wait 等)。

就這個可讀性問題,讓我們介紹一下Eclipse的 JWT 子項目,它旨在提供一個工作流管理(設計、轉換,模擬和連接引擎)的工具。JWT 現(xiàn)在使用 UML活動圖 符號(簡稱UML-AD)設計工作流。UML-AD 嚴格等價于BPMN(就表現(xiàn)力來說)(詳見 [WHITE_UNKNOWN_DATE] )。那么,使用UML-AD符號,我們可以在JWT中把之前的BPMN圖表示為:

JWT是可擴展的,同時提供了不同的轉換插件。其中一個是UML-AD2BPEL轉換,來自Augsburg大學的一個研究項目。這個BPEL轉換插件會輸出一個518行的BPEL-WS-1.1文檔(在這片文章的結尾會提供樣本)。注意,不管是Eclipse BPEL設計器還是Intalio設計器都無法正確地展示這個BPEL文件。鑒于此,我們使用了Netbeans。但產(chǎn)生的圖還是太復雜了,無法在此展現(xiàn)(要了解該圖的局部展現(xiàn),請參見“資源”小節(jié))。為了得到等價的 5 BPEL描述,JWT2BPEL轉換工具大量地使用了BPEL事件。要是有人有勇氣一讀的話,其難度可見一斑。

因此,使用諸如BPMN或者UML-AD這樣純工作流符號表示的簡單并行非結構化流程很難被表示成“可讀”的BPEL格式。這就是一個普通事實,而不是單單是針對我們這里討論的這個簡單流程。在考慮BPMN-to-BPEL雙向工程的情況下,情況更糟:(來自于Wikipedia) “從BPMN圖生成BPEL代碼,維護原始BPMN模型和所產(chǎn)生的BPEL代碼之間的同步,一個中的任何改動都要傳播給另一個”。使用諸如BPMN這樣的自然工作流符號來表示用BPEL作為其最終格式的業(yè)務流程執(zhí)行,無異于沒事找事。

注意,從BPEL流程創(chuàng)建BPMN圖的過程似乎要比其反過程要容易的多:把結構化元素轉化成非結構化相當簡單。注意,在Intalio中已經(jīng)提供了這樣一個轉換(BPEL2BPMN)的Java類,從 這里 可得到。它似乎是以STP的核心,并且(目前)還不是完全地符合BPEL,在類的注釋中能看出來:

;

    /*
    
* 由BPEL文件產(chǎn)生BPMN的非常基本的例子。
* 這里解析的BPEL只是BPEL規(guī)范的一個很小的子集:
* scope、assign、receive、reply、invoke、flow、sequence。
* ...
*/

盡管如此,由于某些未知的原因,導入由Intalio設計器生成的BPEL文件將無法工作。可是,雙向工程的問題在于保持同一流程兩個完全不同的表示的同步:一個是BPMN,另一個是BPEL。

結論

首先,我們澄清了一個常見的誤解:BPEL不是一門結構化語言,但它是基于結構化語言的(基于塊[Block])。在某些方面,BPEL更接近于類似 Java這樣的標準語言,而不是一個自然的工作流符號,比如BPMN(基于圖)。直到現(xiàn)在,程序員都是直接打理他們的語言。集成開發(fā)環(huán)境則用來簡化幾個重復步驟,比如編譯、重構、測試等等。 但是程序員直接“講”他們的語言。我們認為,這種情景將同樣適用于BPEL。一個IDE 只能簡化編程步驟(注意,我們在這里并沒有用“設計”一詞)。但是,為了使用以及從中獲益,BPEL程序員將不得不“講”BPEL。關于BPEL對于大多技術人員是否是“說得出口的”-就像Java一樣-這個問題已經(jīng)超出了本文的范圍,但它確實是一個有趣的問題。

然而對于業(yè)務分析師,BPEL則顯然不夠友好。BPEL難以閱讀、難以學習、難以實現(xiàn),而所有這些正是終端用戶的主要關注點:難以回避。我們已經(jīng)注意到,在文中使用的這個簡單例子中,當創(chuàng)建“Employer”池時,為了生成BPEL文件,我們受制于創(chuàng)建另一個“非執(zhí)行”的池。Intalio設計器中給出的許多其他BPEL相關行頭,從BPMN分析師的角度來看則完全沒有用:比如命名空間、Web服務調用、XML數(shù)據(jù)類型以及其他。

因此,我們認為BPMN符號是業(yè)務分析師目前唯一可用的解決方案 6 。不過,在流程能夠實際執(zhí)行之前仍需指定許多執(zhí)行細節(jié),這是BPMN規(guī)范中所沒有的,并且是分析師在設計時不清楚的。這些信息通常本質上是技術、站點(如:郵件服務器地址、任務庫)或實現(xiàn)(如:Web服務、J2EE服務或.NET 服務)依賴的。因此,技術人員輸入到環(huán)境上下文的流程骨架是一個在執(zhí)行語義(雙向模擬)上等價于原始BPMN流程,并且它還是易讀的以保證所做的修改不會改變流程的行為,這一點是極其重要的。

從BPMN到(可讀的)BPEL轉換相當難以實現(xiàn),并會產(chǎn)生(如果正確的話)難以閱讀的代碼。順便提一下,雙向工程的問題就更難了。除非后者能得以解決,否則無法讓實際業(yè)務分析師把BPEL作為設計流程的目標輸出。

因此,我們很疑惑:既然已經(jīng)存在一種可以直接映射到BPMN各單元的基于圖的標準,即XPDL v2.0,為什么還要將BPMN轉換成BPEL?使用這種映射,XPDL v2.0很自然就成了一種BPMN的持久化文件格式。此外,它還指定了之前只能用在BPEL中的可用行為,如Web服務調用和補償。當然,有人會說,XPDL 2.0缺乏一些執(zhí)行方面的規(guī)范,這就讓它不適合直接執(zhí)行。我們相信,在XPDL沒有詳細說明的地方使用BPEL,為實現(xiàn)一個完全符合BPMN v2.0、XPDL v2.0和BPEL的引擎留下了充足的空間。Bonita和Orchestra團隊正是按這樣方式去實現(xiàn)的他們下一代BPM引擎。但這應該是另一個故事了,需要另一篇文章來介紹……就此打住!

感謝Bonita & Orchestra 團隊對本文的幫助和支持,尤其是Miguel Valdes-Faura的審校和建議。同時也感謝Gavin Terrill的校對和臨門一腳。

Pierre Vignéras

Bull, Architect of an Open World?

*BPM Team*, Bull R & D

參考資料

腳注

  1. 有人會說,程序員也必須處理現(xiàn)實世界的事兒,但他們完全不在同一個抽象層面(否則,為分析師定義特定的符號又有何意義?)。
  2. 當然,我們必須定義“等價”的含義。一般來說,在流程的世界中,使用的正式定義是“雙向模擬(bisimulation)”[MILNER89]。但是鑒于它無法區(qū)分并行執(zhí)行和它的順序模擬(BPM用戶所希望的的),我們就用全并行雙向模擬[EKIE89]概念來替代它。
  3. 參見全并行雙向模擬的概念。
  4. 參見人類可讀的BEPL的公共思想,即,盡量用塊(block)創(chuàng)建。
  5. 順便說一下,實現(xiàn)形式上確實等價(雙向模擬)原始BPMN圖的最終BPEL文件就留給讀者您了……;-)
  6. 可能也可以使用UML-AD符號,因為在表現(xiàn)力上它等價于BPMN。不過,我們還是認為BPMN更貼近BPM分析師的要求。

資源

1. JWT2BPEL轉換輸出了 這個BPEL文件

2. 如果使用NetBeans把上一個資源給出的BPEL流程表示成一張圖,我們會得到 這樣的圖 。該圖表示了整個流程,中間的部分都收縮起來了(節(jié)點用“+”符號表示)。如果我們展開這個節(jié)點,我們會得到 一張展開的圖 。在這個圖中,我們可以看到包含有“+”符號的兩個節(jié)點。它們分別代表了原始BPMN圖中的“Employee Arrival”和“Ready to work”兩個活動。從“Employee Arrival”節(jié)點,我們能夠看到事件所隸屬于的標記為C5的BPEL范圍。在它的右邊,能夠看到那些事件。這些事件被用來以BPEL實現(xiàn)原始BPMN 圖中描述的并行和非結構化流程。

查看英文原文 Why BPEL is not the holy grail for BPM?

轉自:http://www.infoq.com/cn/articles/bpelbpm-cn

BPEL為何不是BPM的圣杯?


更多文章、技術交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 特级毛片在线播放 | 久久久久亚洲香蕉网 | 色综合天天综一个色天天综合网 | 毛片一级在线观看 | 国产精品21区 | 真人视频一级毛片 | 久久精品女人天堂 | 久草免费资源视频 | 999久久66久6只有精品 | 日本阿v精品视频在线观看 日本爱爱免费视频 | 国产亚洲精品激情一区二区三区 | 国产草比| 欧美午夜精品 | 日韩美在线 | 中文字幕日本精品一区二区三区 | 狠狠色丁香久久婷婷 | 爱爱视频免费在线观看 | 国产一区二区久久精品 | 欧美成人午夜在线全部免费 | 亚洲视频在线免费看 | 天天摸天天操天天干 | 国产成人精品日本 | 色妞欧美| 99热精品久久只有精品30 | 国产a级一级久久毛片 | 国产成人女人视频在线观看 | 国产福利视频在线播放 | 国产成人亚洲综合在线 | 99热久久精品首页 | 狠狠色噜噜狠狠狠狠 | 国产精品亚洲国产 | 高清在线一区二区三区亚洲综合 | 美国一级毛片片aa久久综合 | α级毛片 | 国产玖玖视频 | 伊人久久亚洲综合 | 干夜夜 | 久久久久久久久久久福利观看 | 亚洲第一综合网站 | 精品一区 二区三区免费毛片 | 日日做日日摸夜夜爽 |