<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ### 第8章開發者信息 **目錄** Subversion是一個開源的軟件項目,使用Apache樣式的軟件許可證。這個項目由位于加利福尼亞的CollabNet, Inc.軟件開發公司資助。這個關于Subversion開發的社區一直歡迎新成員貢獻自己的時間和注意力。鼓勵志愿者做他們能做的任何幫助,不管是發現和診斷bug,精煉已存的代碼還是補充新的特性。 本章是為那些希望實際參與源代碼編寫來幫助Subversion不斷進步的人們準備的。我們要知道,在這里我們會涉及到許多軟件內在的細節,在開發Subversion本身―或利用Subversion庫開發全新工具時―所用到的許多核心技術。如果你無法預測你是否會以這種層級參與到這個軟件中來,那么也可以隨意跳過這一章,而你作為一個Subversion用戶的體驗不會受到任何影響。 ### 分層的庫設計 Subversion有一個模塊化的設計,通過一套C庫來實現。每一個庫都有一套定義良好的目標與接口,據稱,大部分模塊都屬于三層中的某一層―版本庫層、版本庫訪問(RA)層或是客戶端層。我們很快就會考察這些層,但首先讓我們看一下[表8.1 “Subversion庫的摘要目錄”]中的有關于Subversion庫的摘要目錄,為了一致性,我們將通過它們的無擴展Unix庫名(例如libsvn_fs、libsvn_wc和mod_dav_svn)來引用它們。 **表8.1.Subversion庫的摘要目錄** | 庫 | 描述 | |-----|-----| | libsvn_client | 客戶端程序的主要接口 | | libsvn_delta | 目錄樹和文本區別程序 | | libsvn_fs | Subversion文件系統庫 | | libsvn_fs_base | Berkeley DB文件系統后端 | | libsvn_fs_fs | 本地文件系統(FSFS)后端 | | libsvn_ra | 版本庫訪問通用組件和模塊裝載器 | | libsvn_ra_dav | WebDAV版本庫訪問模塊 | | libsvn_ra_local | 本地版本庫訪問模塊 | | libsvn_ra_svn | 一個自定義版本庫訪問模塊 | | libsvn_repos | 版本庫接口 | | libsvn_subr | 各色各樣的有用的子程序 | | libsvn_wc | 工作拷貝管理庫 | | mod_authz_svn | 使用WebDAV訪問Subversion版本庫的Apache授權模塊 | | mod_dav_svn | 影射WebDAV操作為Subversion操作的Apache模塊 | 單詞“各色各樣的”只在列表[表8.1 “Subversion庫的摘要目錄”]中出現過一次是一個好的跡象。Subversion開發團隊非常注意將功能歸入合適的層和庫,或許模塊化設計最大的好處就是從開發者的角度看減少了復雜性。作為一個開發者,你可以很快就描畫出一副“大圖像”,以便于你更精確地,也相對容易地找出某一功能所在的位置。 模塊化的另一個好處是我們有能力去構造一個全新的,能夠完全實現相同API功能的庫,以替換整個給定的模塊,而又不會影響基礎代碼。在某種意義上,Subversion已經這樣做了。libsvn_ra_dav、libsvn_ra_local和libsvn_ra_svn all都實現了相同的接口,三者均與版本庫層進行通訊―libsvn_ra_dav和libsvn_ra_svn通過網絡,而libsvn_ra_local則是直接連接。 客戶端設計本身就給模塊化設計理念增色不少,Subversion目前只是附帶了一個命令行方式的客戶端,但已經出現了一些由第三方開發的GUI客戶端程序,這些GUI客戶端程序全都使用了與原裝命令行客戶端程序相同的API。為了開發一個實用的Subversion客戶端程序,對于絕大部分功能,僅使用Subversion的libsvn_client庫就夠了(見[“客戶端層”一節])。 ### 版本庫層 當提到Subversion版本庫層時,我們通常會討論兩個庫―版本庫(函數)庫和文件系統(函數)庫。這兩個庫為你的版本控制數據的各個修訂版本提供了存儲和報告機制,該層通過版本庫訪問層連接到客戶層,而且,從Subversion用戶的角度看,這是資料存儲過程中的“鏈接的另一端”。 Subversion文件系統通過libsvn_fs API來訪問,它并不是一個安裝在操作系統之上的內核級的文件系統(例如Linux ext2或NTFS),而是一個虛擬文件系統。它并未將“文件”和“目錄”保存為真實的文件和目錄(也就是用你熟知的shell程序可以瀏覽的那種),而是采用了一種抽象的后端存儲方式,這個后端存儲方式有兩種―一個是Berkeley DB數據庫環境,另一個是普通文件表示。(要了解更多關于版本庫后端的信息,請看[“版本庫數據存儲”一節])。除此之外,開發社區也非常有興趣考慮在Subversion的未來版本 中提供某種使用其它后端數據庫系統的能力,也許是開放式數據庫連接(ODBC)的機制。 libsvn_fs支持的文件系統API包含了所有其他文件系統的功能:你可以創建和刪除文件和目錄、拷貝和移動、修改文件內容等等。它也包含了一些不太常用的特性,如對任意文件和目錄添加、修改和刪除元數據(“properties”)的能力。此外,Subversion文件系統是一個版本化的文件系統,意味著你修改你的目錄樹時,Subversion會記住修改以前的樣子。等等,可以回到所有初始化版本庫之后(且僅僅之后)的版本。 所有你對目錄樹的修改包含在Subversion事務的上下文中,下面描述了修改文件系統的例程: 1. 開始Subversion事務。 1. 作出修改(添加、刪除、屬性修改等等。)。 1. 提交事務。 一旦你提交了你的事務,你的文件系統修改就會永久的作為歷史保存起來,每個這樣的周期會產生一個新的樹,所有的修訂版本都是永遠可以訪問的一個不變的快照。 **事務其它** Subversion的事務概念,特別是在libsvn_fs中的數據庫附近的代碼,很容易與低層提供支持的數據庫事務混淆。兩種類型事務都提供了原子和隔離操作,換句話說,事務給你能力可以用“全部或者沒有”樣式執行一系列的動作―所有的動作都完全成功,或者是所有的*沒有*發生―而且不會干擾別人操作數據。 數據庫事務通常圍繞著一些對數據庫本身的數據修改相關的小操作(如修改表行的內容),Subversion是更大范圍的事務,圍繞著一些高一級的操作,如下一個修訂版本文件系統的一組文件和目錄的修改。如果這還不是很混亂,考慮這個:Subversion在創建Subversion事務(所以如果Subversion創建事務失敗,數據庫會看起來我們從來沒有嘗試創建)時會使用一個數據庫事務! 很幸運的是用戶的文件系統API,數據庫提供的事務支持本身幾乎完全從外表隱藏(也是一個完全模塊化的模式所應該的)。只有當你開始研究文件系統本身的實現時,這些事情才可見(或者是開始感興趣)。 大多數文件系統接口提供的功能作為一個動作發生在一個文件系統路徑上,也就是,從文件系統的外部,描述和訪問文件和目錄獨立版本的主要機制是經過如`/foo/bar`的路徑,就像你在喜歡的shell程序中定位文件和目錄。你通過傳遞它們的路徑到相應的API功能來添加新的文件和目錄,查詢這些信息也是同樣的機制。 不像大多數文件系統,盡管,一個單獨的路徑不足以在Subversion定位一個文件或目錄,可以把目錄樹看作一個二維的系統,一個節點的兄弟代表了一種從左到右的動作,并且遞減到子目錄是一個向下的動作,[圖8.1 “二維的文件目錄”]展示了一個典型的樹的形式。 **圖8.1.二維的文件目錄** ![二維的文件目錄](https://box.kancloud.cn/2016-08-21_57b8a334c4bf6.png) 當然,Subversion文件系統有一個其它文件系統所沒有的第三維―時間! 在一個文件系統接口,幾乎所有的功能都有個*`路徑`*參數,也期望一個*`root`*參數。svn_fs_root_t參數不僅描述了一個修訂版本或一個Subversion事務(通常正好是一個修訂版本),而且提供了用來區分修訂版本32的`/foo/bar`和修訂版本98在同樣路徑的三維上下文環境。[圖8.2 “版本時間―第三維!”]展示了修訂版本歷史作為添加的緯度進入到Subversion文件系統領域。 **圖8.2.版本時間―第三維!** ![版本時間―第三維!](https://box.kancloud.cn/2016-08-21_57b8a334d9b17.png) 像之前我們提到的,libsvn_fs的API感覺像是其它文件系統,只是有一個美妙的版本化能力。它設計為為所有對版本化的文件系統有興趣的程序使用,不是巧合,Subversion本身也對這個功能很有興趣。但是雖然文件系統API一定必須對基本的文件和目錄版本化提供足夠的支持,Subversion需要的更多―這是libsvn_repos到來的地方。 Subversion版本庫庫(libsvn_repos)是文件系統功能的一個基本包裹庫,這個庫負責創建版本庫布局,確定底層的文件系統已經初始化等等。Libsvn_repos也實現了一組鉤子―當特定動作發生時版本庫執行的腳本。這些腳本用來通知,授權或者任何版本庫管理員期望的目的。版本庫庫提供的這些功能和小工具與版本化的文件系統關系不大,所以放到了自己的庫里。 希望使用libsvn_repos的API的開發者會發現它不是文件系統的一個完全包裹,只有文件系統常規周期中的主要事件使用版本庫接口包裹,如包括Subversion事務的創建和提交,修訂版本屬性的修改。這些特別的事件使用版本庫庫包裹是因為它們有一些關聯的鉤子,在將來,別的事件也將會使用版本庫API包裹。所有其它的文件系統交互會直接通過libsvn_fs的API發生。 舉個例子,這里是使用版本庫和文件系統接口創建文件系統新修訂版本的代碼塊,新版本包括添加一個新目錄。注意這個例子(和其它本書中的代碼),這個`SVN_ERR`宏只是簡單的檢查是否有一個非成功的錯誤從包裹的函數中返回,如果存在就會返回錯誤。 **例8.1.使用版本庫層** ~~~ /* Create a new directory at the path NEW_DIRECTORY in the Subversion repository located at REPOS_PATH. Perform all memory allocation in POOL. This function will create a new revision for the addition of NEW_DIRECTORY. */ static svn_error_t * make_new_directory (const char *repos_path, const char *new_directory, apr_pool_t *pool) { svn_error_t *err; svn_repos_t *repos; svn_fs_t *fs; svn_revnum_t youngest_rev; svn_fs_txn_t *txn; svn_fs_root_t *txn_root; const char *conflict_str; /* Open the repository located at REPOS_PATH. */ SVN_ERR (svn_repos_open (&repos, repos_path, pool)); /* Get a pointer to the filesystem object that is stored in REPOS. */ fs = svn_repos_fs (repos); /* Ask the filesystem to tell us the youngest revision that currently exists. */ SVN_ERR (svn_fs_youngest_rev (&youngest_rev, fs, pool)); /* Begin a new transaction that is based on YOUNGEST_REV. We are less likely to have our later commit rejected as conflicting if we always try to make our changes against a copy of the latest snapshot of the filesystem tree. */ SVN_ERR (svn_fs_begin_txn (&txn, fs, youngest_rev, pool)); /* Now that we have started a new Subversion transaction, get a root object that represents that transaction. */ SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool)); /* Create our new directory under the transaction root, at the path NEW_DIRECTORY. */ SVN_ERR (svn_fs_make_dir (txn_root, new_directory, pool)); /* Commit the transaction, creating a new revision of the filesystem which includes our added directory path. */ err = svn_repos_fs_commit_txn (&conflict_str, repos, &youngest_rev, txn, pool); if (! err) { /* No error Excellent! Print a brief report of our success. */ printf ("Directory '%s' was successfully added as new revision " "'%ld'.\n", new_directory, youngest_rev); } else if (err->apr_err == SVN_ERR_FS_CONFLICT) { /* Uh-oh. Our commit failed as the result of a conflict (someone else seems to have made changes to the same area of the filesystem that we tried to modify). Print an error message. */ printf ("A conflict occurred at path '%s' while attempting " "to add directory '%s' to the repository at '%s'.\n", conflict_str, new_directory, repos_path); } else { /* Some other error has occurred. Print an error message. */ printf ("An error occurred while attempting to add directory '%s' " "to the repository at '%s'.\n", new_directory, repos_path); } /* Return the result of the attempted commit to our caller. */ return err; } ~~~ 在前面的代碼片斷中,同時調用了版本庫和文件系統接口,我們可以正像這樣簡單的用`svn_fs_commit_txn`提交事務。但是文件系統的API對版本庫庫的鉤子一無所知,如果你希望你的Subversion版本庫在每次提交一個事務時自動執行一些非Subversion的任務(例如,給開發者郵件組發送一個描述事務修改的郵件),你需要使用libsvn_repos包裹的功能版本―`svn_repos_fs_commit_txn`。這個功能會實際上首先運行一個如果存在的`pre-commit`鉤子腳本,然后提交事務,最后會運行一個`post-commit`鉤子腳本。鉤子提供了一種特別的報告機制,不是真的屬于核心文件系統庫本身。(關于Subversion版本庫鉤子的更多信息,見[“鉤子腳本”一節]。) 鉤子機制需求是從文件系統代碼的其它部分中抽象出單獨的版本庫庫的一個原因,libsvn_repos的API提供了許多其他有用的工具,它們可以做到: 1. 在Subversion版本庫和版本庫包括的文件系統的上創建、打開、銷毀和執行恢復步驟。 1. 描述兩個文件系統樹的區別。 1. 關于所有(或者部分)修訂版本中的文件系統中的一組文件的提交日志信息的查詢 1. 產生可讀的文件系統“導出”,一個文件系統修訂版本的完整展現。 1. 解析導出格式,加載導出的版本到一個不同的Subversion版本庫。 伴隨著Subversion的發展,版本庫庫會隨著文件系統提供更多的功能和配置選項而不斷成長。 ### 版本庫訪問層 如果說Subversion版本庫層是在“這條線的另一端”,那版本庫訪問層就是這條線。負責在客戶端庫和版本庫之間編碼數據,這一層包括libsvn_ra模塊加載模塊,RA模塊本身(現在包括了libsvn_ra_dav、libsvn_ra_local和libsvn_ra_svn),和所有一個或多個RA模塊需要的附加庫,例如與Apache模塊mod_dav_svn通訊的libsvn_ra_dav或者是libsvn_ra_svn的服務器,**svnserve**。 因為Subversion使用URL來識別版本庫資源,URL模式的協議部分(通常是`file:`、`http:`、`https:`或`svn:`)用來監測那個RA模塊用來處理通訊。每個模塊注冊一組它們知道如何“說話”的協議,所以RA加載器可以在運行中監測在手邊的任務中使用哪個模塊。通過運行**svn --version**,你可以監測Subversion命令行客戶端所支持的RA模塊和它們聲明支持的協議: ~~~ $ svn --version svn, version 1.0.1 (r9023) compiled Mar 17 2004, 09:31:13 Copyright (C) 2000-2004 CollabNet. Subversion is open source software, see http://subversion.tigris.org/ This product includes software developed by CollabNet (http://www.Collab.Net/). The following repository access (RA) modules are available: * ra_dav : Module for accessing a repository via WebDAV (DeltaV) protocol. - handles 'http' schema - handles 'https' schema * ra_local : Module for accessing a repository on local disk. - handles 'file' schema * ra_svn : Module for accessing a repository using the svn network protocol. - handles 'svn' schema ~~~ #### RA-DAV(使用HTTP/DAV版本庫訪問) libsvn_ra_dav庫是給在不同機器使用`http:`或`https:`協議訪問服務器的用戶設計的,為了理解這個模塊的工作,我們首先要知道這種版本庫訪問層中的特定配置的關鍵組成部分―強大的Apache HTTP服務器,和Neon HTTP/WebDAV客戶端庫。 Subversion的主要網絡服務器是Apache HTTP服務器,Apache是久經考驗的用來認真使用的開源服務器,它可以支撐很大的網絡壓力并且可以運行在多種平臺。Apache服務器支持多種認證協議,而且可以通過模塊擴展使用其它協議。它也支持流水線和緩存之類的網絡優化。通過將Apache作為服務器,Subversion輕易得到這些特性。而且因為許多防火墻已經允許HTTP通過,系統管理員通常不會改變防火墻設置來允許Subversion工作。 Subversion使用HTTP和WebDAV(和DeltaV)來與Apache服務器通訊,你可以在本章的WebDAV讀到更多信息,但簡而言之,WebDAV和DeltaV是標準HTTP 1.1協議的擴展,允許在web上對文件進行分享和版本操作。Apache 2.0版隨著一個mod_dav,一個Apache理解HTTP DAV擴展的模塊,Subversion本身提供了mod_dav_svn,盡管,這是另一個Apache模塊,它與mod_dav結合(實際上mod_dav_svn是作為后端支持)使用來提供Subversion對WebDAV和DeltaV的實現。 當與版本庫通過HTTP通訊時,RA加載器庫選擇libsvn_ra_dav作為正確的訪問模塊,Subversion客戶端調用原始的RA接口,libsvn_ra_dav把這些調用(包含了大量Subversion操作)影射為一系列HTTP/WebDAV請求。使用Neon庫,libsvn_ra_dav把這些請求傳遞到Apache服務器,Apache接受到這些請求(就像平時web服務器常做的那樣處理原始的HTTP請求),注意到這些請求的URL已經配置為DAV的位置(使用`httpd.conf`的`Location`指示),并且會使用自己的mod_dav模塊來處理。當正確的配置了mod_dav使之知道了使用mod_dav_svn來處理所有文件系統相關的要求,而不是使用默認的Apache自帶的原始mod_dav_fs來處理。所以最終客戶端是與mod_dav_svn通訊,直接與Subversion版本庫層綁定。 有一個實際交換發生的簡單描述,舉個例子,Subversion版本庫可以使用Apache的授權指示進行保護。這會導致初始的與版本庫的通訊會被Apache的授權基礎拒絕,在此刻,libsvn_ra_dav將提供不足鑒定的通知返回,并且回調客戶端層來得到一些更新的認證數據。如果數據是正確提供,而且用戶有訪問的權限,會賦予libsvn_ra_dav的下一個對原操作的自動嘗試權限,并且一切會很好。如果足夠的認證信息不能提供,請求會最后失敗,客戶端也會報告給用戶失敗信息。 通過使用Neon和Apache,Subversion在許多其它領域的輕易得到復雜的功能。舉個例子,如果Neon找到OpenSSL庫,它允許Subversion客戶端嘗試與Apache服務器(它自己的mod_ssl“可以說這個語言”)使用SSL加密的通訊。Neon本身和Apache的mod_deflate都可以理解“deflate”算法(PKZIP和gzip共同使用的程序),所以請求可以壓縮塊方式傳輸。其它Subversion今后希望支持的復雜特性包括,自動處理服務器重定向(舉個例子,當版本庫轉移到一個新的規范URL)和利用HTTP流水線的能力。 #### RA-SVN(自定義協議版本庫訪問) 作為標準HTTP/WebDAV協議的補充,Subversion也提供了一個使用自定義協議的RA實現,libsvn_ra_svn模塊實現了自己的網絡套接字連接,與一個獨立服務器通訊―`svnserve`程序―在存放版本庫的機器上。客戶端可以使用`svn://`訪問版本庫。 這個RA實現缺乏前面小節提到的Apache的大多數優點;然而雖然如此,系統管理員會非常有興趣,因為這配置和運行異常的簡單;設置一個`svnserve`幾乎是立刻的,它與Apache相比也是非常的小(從代碼長度這方面說),讓它非常容易進行安全或其它方面原因的審核。此外,一些系統管理員或許已經有了一個SSH安全基礎,希望Subversion使用它,客戶端使用ra_svn可以容易的使用SSH封裝這個協議。 #### RA-Local(直接版本庫訪問) 并不是所有與Subversion版本庫的通訊需要服務器進程和一個網絡層。用戶如果只是希望簡單的訪問本地磁盤的版本庫,他們會使用`file:`的URL和libsvn_ra_local提供的功能。RA模塊直接與版本庫和文件系統庫綁定,所以不需要網絡通訊。 Subversion需要服務器名稱成為`file:`的URL的一部分,是`localhost`或者是為空。換句話說,你的URL必須看起來如`file://localhost/path/to/repos`或者`file:///path/to/repos`。 也必須意識到Subversion的`file:` URL不能和在普通的web服務器中的`file:` URL一樣工作。當你嘗試在web服務器查看一個`file:`的URL,它會通過直接檢測文件系統讀取和顯示那個位置的文件內容,但是Subversion的資源存在于虛擬文件系統(見[“版本庫層”一節])中,你的瀏覽器不會理解怎樣讀取這個文件系統。 #### 你的RA庫在這里 對那些一直希望使用另一個協議來訪問Subversion版本庫的人,正好是為什么版本庫訪問層是模塊化的!開發者可以簡單的編寫一個新的庫來在一側實現RA接口并且與另一側的版本庫通訊。你的新庫可以使用存在的網絡協議,或者發明你自己的。你可以使用進程間的通訊調用,或者―讓我們發狂,我們會嗎?―你甚至可以實現一個電子郵件為基礎的協議,Subversion提供了API,你提供創造性。 ### 客戶端層 在客戶端這一面,Subversion工作拷貝是所有動作發生的地方。大多數客戶端庫實現的功能是為了管理工作拷貝的目的實現的―滿是文件子目錄的目錄是一個或多個版本庫位置的可編輯的本地“影射”―從版本庫訪問層來回傳遞修改。 Subversion的工作拷貝庫,libsvn_wc直接負責管理工作拷貝的數據,為了完成這一點,庫會在工作拷貝的每個目錄的特殊子目錄中保存關于工作拷貝的管理性信息。這個子目錄叫做`.svn`,出現在所有工作拷貝目錄里,保存了各種記錄了狀態和用來在私有工作區工作的文件和目錄。對那些熟悉CVS的用戶,`.svn`子目錄與`CVS`工作拷貝管理目錄的作用類似,關于`.svn`管理區域的更多信息,見本章的[“進入工作拷貝的管理區”一節]。 Subversion客戶端庫libsvn_client具備最廣泛的職責;它的工作是結合工作拷貝庫和版本庫訪問庫的功能,然后為希望普通版本控制的應用提供最高級的API。舉個例子,`svn_client_checkout`方法是用一個URL作為參數,傳遞這個URL到RA層然后在特定版本庫打開一個會話。然后向版本庫要求一個特定的目錄樹,然后把目錄樹發送給工作拷貝庫,然后把完全的工作拷貝寫到磁盤(`.svn`目錄和一切)。 客戶端庫是為任何程序使用設計的,盡管Subversion的源代碼包括了一個標準的命令行客戶端,用客戶端庫編寫GUI客戶端也是很簡單,Subversion新的GUI(或者任何新的客戶端,真的)不需要緊密圍繞包含的命令行客戶端―他們對具有相同功能、數據和回調機制的libsvn_client的API有完全的訪問權利。 **直接綁定―關于正確性** 為什么GUI程序要直接訪問libsvn_client而不以命令行客戶端的包裹運行?除了效率以外,這也關系到潛在的正確性問題。一個命令行客戶端程序(如Subversion提供的)如果綁定了客戶端庫,需要將反饋和請求數據字節從C翻譯為可讀的輸出,這種翻譯是有損耗的,程序不能得到API所提供的所有信息,或者是得到緊湊的信息。 如果你已經包裹了這樣一個命令行程序,第二個程序只能訪問已經經過解釋的(如我們提到的,不完全)信息,需要*再次*轉化為*它本身的*展示格式。由于各層的包裹,原始數據的完整性越來越難以保證,結果很像對喜歡的錄音帶或錄像帶反復的拷貝(一個拷貝…)。 譯者:這里的“庫(library)”指函數庫,與文中大量出現的“版本庫(Repository)”不同,一般情況下,作為獨詞出現的“庫”應屬于前者。 我們理解這一定會給科幻小說迷帶來一個震撼,他們認為時間是*第四*維的,我們要為提出這樣一個不同理論的斷言而傷害了他們的作出道歉。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看