亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 網站 > 建站經驗 > 正文

深入解析PHP的Yii框架中的緩存功能

2024-08-30 19:06:49
字體:
來源:轉載
供稿:網友

數據緩存是指將一些 PHP 變量存儲到緩存中,使用時再從緩存中取回。它也是更高級緩存特性的基礎,例如查詢緩存和內容緩存。

如下代碼是一個典型的數據緩存使用模式。其中 $cache 指向緩存組件:

  1. // 嘗試從緩存中取回 $data  
  2.  
  3. $data = $cache->get($key); 
  4.  
  5. if ($data === false) { 
  6.  
  7.   // $data 在緩存中沒有找到,則重新計算它的值 
  8.  
  9.  //Vevb.com 
  10.  
  11.   // 將 $data 存放到緩存供下次使用 
  12.  
  13.   $cache->set($key$data); 
  14.  
  15. } 
  16.  
  17. // 這兒 $data 可以使用了。 

緩存組件

數據緩存需要緩存組件提供支持,它代表各種緩存存儲器,例如內存,文件,數據庫。

緩存組件通常注冊為應用程序組件,這樣它們就可以在全局進行配置與訪問。如下代碼演示了如何配置應用程序組件 cache 使用兩個 memcached 服務器:

  1. 'components' => [ 
  2.  
  3.   'cache' => [ 
  4.  
  5.     'class' => 'yii/caching/MemCache'
  6.  
  7.     'servers' => [ 
  8.  
  9.       [ 
  10.  
  11.         'host' => 'server1'
  12.  
  13.         'port' => 11211, 
  14.  
  15.         'weight' => 100, 
  16.  
  17.       ], 
  18.  
  19.       [ 
  20.  
  21.         'host' => 'server2'
  22.  
  23.         'port' => 11211, 
  24.  
  25.         'weight' => 50, 
  26.  
  27.       ], 
  28.  
  29.     ], 
  30.  
  31.   ], 
  32.  
  33. ], 

然后就可以通過 Yii::$app->cache 訪問上面的緩存組件了。

由于所有緩存組件都支持同樣的一系列 API ,并不需要修改使用緩存的業務代碼就能直接替換為其他底層緩存組件,只需在應用配置中重新配置一下就可以。例如,你可以將上述配置修改為使用 yii/caching/ApcCache:

  1. 'components' => [ 
  2.  
  3.   'cache' => [ 
  4.  
  5.     'class' => 'yii/caching/ApcCache'
  6.  
  7.   ], 
  8.  
  9. ], 

Tip: 你可以注冊多個緩存組件,很多依賴緩存的類默認調用名為 cache 的組件(例如 yii/web/UrlManager)。

支持的緩存存儲器

Yii 支持一系列緩存存儲器,概況如下:

yii/caching/ApcCache:使用 PHP APC 擴展。這個選項可以認為是集中式應用程序環境中(例如:單一服務器,沒有獨立的負載均衡器等)最快的緩存方案。

yii/caching/DbCache:使用一個數據庫的表存儲緩存數據。要使用這個緩存,你必須創建一個與 yii/caching/DbCache::cacheTable 對應的表。

yii/caching/DummyCache: 僅作為一個緩存占位符,不實現任何真正的緩存功能。這個組件的目的是為了簡化那些需要查詢緩存有效性的代碼。例如,在開發中如果服務器沒有實際的緩存支持,用它配置一個緩存組件。一個真正的緩存服務啟用后,可以再切換為使用相應的緩存組件。兩種條件下你都可以使用同樣的代碼 Yii::$app->cache->get($key) 嘗試從緩存中取回數據而不用擔心 Yii::$app->cache 可能是 null。

yii/caching/FileCache:使用標準文件存儲緩存數據。這個特別適用于緩存大塊數據,例如一個整頁的內容。

yii/caching/MemCache:使用 PHP memcache 和 memcached 擴展。這個選項被看作分布式應用環境中(例如:多臺服務器,有負載均衡等)最快的緩存方案。

yii/redis/Cache:實現了一個基于 Redis 鍵值對存儲器的緩存組件(需要 redis 2.6.12 及以上版本的支持 )。

yii/caching/WinCache:使用 PHP WinCache(另可參考)擴展.

yii/caching/XCache:使用 PHP XCache擴展。

yii/caching/ZendDataCache:使用 Zend Data Cache 作為底層緩存媒介。

Tip: 你可以在同一個應用程序中使用不同的緩存存儲器。一個常見的策略是使用基于內存的緩存存儲器存儲小而常用的數據(例如:統計數據),使用基于文件或數據庫的緩存存儲器存儲大而不太常用的數據(例如:網頁內容)。

緩存 API

所有緩存組件都有同樣的基類 yii/caching/Cache ,因此都支持如下 API:

yii/caching/Cache::get():通過一個指定的鍵(key)從緩存中取回一項數據。如果該項數據不存在于緩存中或者已經過期/失效,則返回值 false。

yii/caching/Cache::set():將一項數據指定一個鍵,存放到緩存中。

yii/caching/Cache::add():如果緩存中未找到該鍵,則將指定數據存放到緩存中。

yii/caching/Cache::mget():通過指定的多個鍵從緩存中取回多項數據。

yii/caching/Cache::mset():將多項數據存儲到緩存中,每項數據對應一個鍵。

yii/caching/Cache::madd():將多項數據存儲到緩存中,每項數據對應一個鍵。如果某個鍵已經存在于緩存中,則該項數據會被跳過。

yii/caching/Cache::exists():返回一個值,指明某個鍵是否存在于緩存中。

yii/caching/Cache::delete():通過一個鍵,刪除緩存中對應的值。

yii/caching/Cache::flush():刪除緩存中的所有數據。

有些緩存存儲器如 MemCache,APC 支持以批量模式取回緩存值,這樣可以節省取回緩存數據的開支。 yii/caching/Cache::mget() 和 yii/caching/Cache::madd() API提供對該特性的支持。如果底層緩存存儲器不支持該特性,Yii 也會模擬實現。

由于 yii/caching/Cache 實現了 PHP ArrayAccess 接口,緩存組件也可以像數組那樣使用,下面是幾個例子:

  1. $cache['var1'] = $value1// 等價于: $cache->set('var1', $value1); 
  2.  
  3. $value2 = $cache['var2']; // 等價于: $value2 = $cache->get('var2'); 

緩存鍵

存儲在緩存中的每項數據都通過鍵作唯一識別。當你在緩存中存儲一項數據時,必須為它指定一個鍵,稍后從緩存中取回數據時,也需要提供相應的鍵。

你可以使用一個字符串或者任意值作為一個緩存鍵。當鍵不是一個字符串時,它將會自動被序列化為一個字符串。

定義一個緩存鍵常見的一個策略就是在一個數組中包含所有的決定性因素。例如,yii/db/Schema 使用如下鍵存儲一個數據表的結構信息。

  1.  
  2.   __CLASS__,       // 結構類名 
  3.  
  4.   $this->db->dsn,     // 數據源名稱 
  5.  
  6.   $this->db->username,  // 數據庫登錄用戶名 
  7.  
  8.   $name,         // 表名 
  9.  
  10. ]; 

如你所見,該鍵包含了可唯一指定一個數據庫表所需的所有必要信息。

當同一個緩存存儲器被用于多個不同的應用時,應該為每個應用指定一個唯一的緩存鍵前綴以避免緩存鍵沖突??梢酝ㄟ^配置 yii/caching/Cache::keyPrefix 屬性實現。例如,在應用配置中可以編寫如下代碼:

  1. 'components' => [ 
  2.  
  3.   'cache' => [ 
  4.  
  5.     'class' => 'yii/caching/ApcCache'
  6.  
  7.     'keyPrefix' => 'myapp',    // 唯一鍵前綴 
  8.  
  9.   ], 
  10.  
  11. ], 

為了確?;ネㄐ?,此處只能使用字母和數字。

緩存過期

默認情況下,緩存中的數據會永久存留,除非它被某些緩存策略強制移除(例如:緩存空間已滿,最老的數據會被移除)。要改變此特性,你可以在調用 yii/caching/Cache::set() 存儲一項數據時提供一個過期時間參數。該參數代表這項數據在緩存中可保持有效多少秒。當你調用 yii/caching/Cache::get() 取回數據時,如果它已經過了超時時間,該方法將返回 false,表明在緩存中找不到這項數據。例如:

  1. // 將數據在緩存中保留 45 秒 
  2.  
  3. $cache->set($key$data, 45); 
  4.  
  5. sleep(50); 
  6.  
  7. $data = $cache->get($key); 
  8.  
  9. if ($data === false) { 
  10.  
  11.   // $data 已過期,或者在緩存中找不到 
  12.  

緩存依賴

除了超時設置,緩存數據還可能受到緩存依賴的影響而失效。例如,yii/caching/FileDependency 代表對一個文件修改時間的依賴。這個依賴條件發生變化也就意味著相應的文件已經被修改。因此,緩存中任何過期的文件內容都應該被置為失效狀態,對 yii/caching/Cache::get() 的調用都應該返回 false。

緩存依賴用 yii/caching/Dependency 的派生類所表示。當調用 yii/caching/Cache::set() 在緩存中存儲一項數據時,可以同時傳遞一個關聯的緩存依賴對象。例如:

  1. // 創建一個對 example.txt 文件修改時間的緩存依賴 
  2.  
  3. $dependency = new /yii/caching/FileDependency(['fileName' => 'example.txt']); 
  4.  
  5. // 緩存數據將在30秒后超時 
  6.  
  7. // 如果 example.txt 被修改,它也可能被更早地置為失效狀態。 
  8.  
  9. $cache->set($key$data, 30, $dependency); 
  10. //Vevb.com 
  11.  
  12. // 緩存會檢查數據是否已超時。 
  13.  
  14. // 它還會檢查關聯的依賴是否已變化。 
  15.  
  16. // 符合任何一個條件時都會返回 false。 
  17.  
  18. $data = $cache->get($key); 

下面是可用的緩存依賴的概況:

yii/caching/ChainedDependency:如果依賴鏈上任何一個依賴產生變化,則依賴改變。

yii/caching/DbDependency:如果指定 SQL 語句的查詢結果發生了變化,則依賴改變。

yii/caching/ExpressionDependency:如果指定的 PHP 表達式執行結果發生變化,則依賴改變。

yii/caching/FileDependency:如果文件的最后修改時間發生變化,則依賴改變。

yii/caching/GroupDependency:將一項緩存數據標記到一個組名,你可以通過調用 yii/caching/GroupDependency::invalidate() 一次性將相同組名的緩存全部置為失效狀態。

查詢緩存

查詢緩存是一個建立在數據緩存之上的特殊緩存特性。它用于緩存數據庫查詢的結果。

查詢緩存需要一個 yii/db/Connection 和一個有效的 cache 應用組件。查詢緩存的基本用法如下,假設 $db 是一個 yii/db/Connection 實例:

  1. $duration = 60;   // 緩存查詢結果60秒 
  2.  
  3. $dependency = ...; // 可選的緩存依賴 
  4.  
  5. $db->beginCache($duration$dependency); 
  6.  
  7. // ...這兒執行數據庫查詢... 
  8.  
  9. $db->endCache(); 

如你所見,beginCache() 和 endCache() 中間的任何查詢結果都會被緩存起來。如果緩存中找到了同樣查詢的結果,則查詢會被跳過,直接從緩存中提取結果。

查詢緩存可以用于 ActiveRecord 和 DAO。

Info: 有些 DBMS (例如:MySQL)也支持數據庫服務器端的查詢緩存。你可以選擇使用任一查詢緩存機制。上文所述的查詢緩存的好處在于你可以指定更靈活的緩存依賴因此可能更加高效。

配置

查詢緩存有兩個通過 yii/db/Connection 設置的配置項:

yii/db/Connection::queryCacheDuration: 查詢結果在緩存中的有效期,以秒表示。如果在調用 yii/db/Connection::beginCache() 時傳遞了一個顯式的時值參數,則配置中的有效期時值會被覆蓋。

yii/db/Connection::queryCache: 緩存應用組件的 ID。默認為 'cache'。只有在設置了一個有效的緩存應用組件時,查詢緩存才會有效。

限制條件

當查詢結果中含有資源句柄時,查詢緩存無法使用。例如,在有些 DBMS 中使用了 BLOB 列的時候,緩存結果會為該數據列返回一個資源句柄。

有些緩存存儲器有大小限制。例如,memcache 限制每條數據最大為 1MB。因此,如果查詢結果的大小超出了該限制,則會導致緩存失敗。

片段緩存

片段緩存指的是緩存頁面內容中的某個片段。例如,一個頁面顯示了逐年銷售額的摘要表格,可以把表格緩存下來,以消除每次請求都要重新生成表格的耗時。片段緩存是基于數據緩存實現的。

在視圖中使用以下結構啟用片段緩存:

  1. if ($this->beginCache($id)) { 
  2.  
  3.   // ... 在此生成內容 ... 
  4.  
  5.   $this->endCache(); 
  6.  

調用 yii/base/View::beginCache() 和 yii/base/View::endCache() 方法包裹內容生成邏輯。如果緩存中存在該內容,yii/base/View::beginCache() 方法將渲染內容并返回 false,因此將跳過內容生成邏輯。否則,內容生成邏輯被執行,一直執行到 yii/base/View::endCache() 時,生成的內容將被捕獲并存儲在緩存中。

和[數據緩存]一樣,每個片段緩存也需要全局唯一的 $id 標記。

緩存選項

如果要為片段緩存指定額外配置項,請通過向 yii/base/View::beginCache() 方法第二個參數傳遞配置數組。在框架內部,該數組將被用來配置一個 yii/widget/FragmentCache 小部件用以實現片段緩存功能。

過期時間(duration)

或許片段緩存中最常用的一個配置選項就是 yii/widgets/FragmentCache::duration 了。它指定了內容被緩存的秒數。以下代碼緩存內容最多一小時:

  1. if ($this->beginCache($id, ['duration' => 3600])) { 
  2.  
  3.   // ... 在此生成內容 ... 
  4.  
  5.   $this->endCache(); 
  6.  

如果該選項未設置,則默認為 0,永不過期。

依賴

和[數據緩存]一樣,片段緩存的內容一樣可以設置緩存依賴。例如一段被緩存的文章,是否重新緩存取決于它是否被修改過。

通過設置 yii/widgets/FragmentCache::dependency 選項來指定依賴,該選項的值可以是一個 yii/caching/Dependency 類的派生類,也可以是創建緩存對象的配置數組。以下代碼指定了一個片段緩存,它依賴于 update_at 字段是否被更改過的。

  1. $dependency = [ 
  2.  
  3.   'class' => 'yii/caching/DbDependency'
  4.  
  5.   'sql' => 'SELECT MAX(updated_at) FROM post'
  6.  
  7. ];  
  8.  
  9. if ($this->beginCache($id, ['dependency' => $dependency])) {  
  10.  
  11.   // ... 在此生成內容 ...  
  12.  
  13.   $this->endCache(); 
  14.  

變化

緩存的內容可能需要根據一些參數的更改而變化。例如一個 Web 應用支持多語言,同一段視圖代碼也許需要生成多個語言的內容。因此可以設置緩存根據應用當前語言而變化。

通過設置 yii/widgets/FragmentCache::variations 選項來指定變化,該選項的值應該是一個標量,每個標量代表不同的變化系數。例如設置緩存根據當前語言而變化可以用以下代碼:

  1. if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) { 
  2.  
  3.   // ... 在此生成內容 ... 
  4.  
  5.   $this->endCache(); 
  6.  

開關

有時你可能只想在特定條件下開啟片段緩存。例如,一個顯示表單的頁面,可能只需要在初次請求時緩存表單(通過 GET 請求)。隨后請求所顯示(通過 POST 請求)的表單不該使用緩存,因為此時表單中可能包含用戶輸入內容。鑒于此種情況,可以使用 yii/widgets/FragmentCache::enabled 選項來指定緩存開關,如下所示:

  1. if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) { 
  2.  
  3.   // ... 在此生成內容 ... 
  4.  
  5.   $this->endCache(); 
  6.  

緩存嵌套

片段緩存可以被嵌套使用。一個片段緩存可以被另一個包裹。例如,評論被緩存在里層,同時整個評論的片段又被緩存在外層的文章中。以下代碼展示了片段緩存的嵌套使用:

  1. if ($this->beginCache($id1)) { 
  2.  
  3.   // ...在此生成內容... 
  4.  
  5.   if ($this->beginCache($id2$options2)) { 
  6.  
  7.     // ...在此生成內容... 
  8.  
  9.     $this->endCache(); 
  10.  
  11.   } 
  12.  
  13.   // ...在此生成內容... 
  14.  
  15.   $this->endCache(); 
  16.  

可以為嵌套的緩存設置不同的配置項。例如,內層緩存和外層緩存使用不同的過期時間。甚至當外層緩存的數據過期失效了,內層緩存仍然可能提供有效的片段緩存數據。但是,反之則不然。如果外層片段緩存沒有過期而被視為有效,此時即使內層片段緩存已經失效,它也將繼續提供同樣的緩存副本。因此,你必須謹慎處理緩存嵌套中的過期時間和依賴,否則外層的片段很有可能返回的是不符合你預期的失效數據。

譯注:外層的失效時間應該短于內層,外層的依賴條件應該低于內層,以確保最小的片段,返回的是最新的數據。

動態內容

使用片段緩存時,可能會遇到一大段較為靜態的內容中有少許動態內容的情況。例如,一個顯示著菜單欄和當前用戶名的頁面頭部。還有一種可能是緩存的內容可能包含每次請求都需要執行的 PHP 代碼(例如注冊資源包的代碼)。這兩個問題都可以使用動態內容功能解決。

動態內容的意思是這部分輸出的內容不該被緩存,即便是它被包裹在片段緩存中。為了使內容保持動態,每次請求都執行 PHP 代碼生成,即使這些代碼已經被緩存了。

可以在片段緩存中調用 yii/base/View::renderDynamic() 去插入動態內容,如下所示:

  1. if ($this->beginCache($id1)) { 
  2.  
  3.   // ...在此生成內容... 
  4.  
  5.   echo $this->renderDynamic('return Yii::$app->user->identity->name;'); 
  6.  
  7.   // ...在此生成內容... 
  8.  
  9.   $this->endCache(); 
  10.  

yii/base/View::renderDynamic() 方法接受一段 PHP 代碼作為參數。代碼的返回值被看作是動態內容。這段代碼將在每次請求時都執行,無論其外層的片段緩存是否被存儲。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美一级bbbbb性bbbb喷潮片| 日本三级久久久| 欧美激情精品久久久久久久变态| 欧美性猛交xxxx富婆| 亚洲福利影片在线| 这里只有精品在线播放| 国产精品国模在线| 欧美精品激情blacked18| 日韩欧美亚洲一二三区| 国产日韩精品在线观看| 亚洲综合精品一区二区| 黑人狂躁日本妞一区二区三区| 亚洲国产另类久久精品| 91视频8mav| 亚洲精品99久久久久中文字幕| 91麻豆国产精品| 久久成人在线视频| 成人免费大片黄在线播放| 亚洲激情视频在线观看| 亚洲最新av在线网站| 欧美二区乱c黑人| 国产成人精品久久二区二区| 精品久久在线播放| 欧美日韩在线视频首页| 日韩av网站电影| 国模gogo一区二区大胆私拍| 亚洲bt欧美bt日本bt| 日韩在线观看网址| 亚洲va欧美va国产综合久久| 日韩av综合中文字幕| 国产成人久久久| 中文亚洲视频在线| 日韩欧美一区视频| 国产精品你懂得| 国产精品丝袜久久久久久高清| 国产精品国产三级国产专播精品人| 国产在线播放91| 亚洲精品91美女久久久久久久| 色爱精品视频一区| 日本中文字幕不卡免费| 啊v视频在线一区二区三区| 91免费看片网站| 亚洲一区二区久久久| 国产精品第3页| 中文字幕无线精品亚洲乱码一区| 欧美日韩在线视频首页| 久久综合久中文字幕青草| 福利微拍一区二区| 欧美孕妇孕交黑巨大网站| 亚洲最大福利视频网站| 日韩在线视频导航| 亚洲激情在线观看视频免费| 色琪琪综合男人的天堂aⅴ视频| 日韩视频免费观看| 日韩av在线影视| 欧美性极品xxxx娇小| 亚洲综合国产精品| 91精品国产91久久久久福利| 日本久久91av| 久久久久久久国产| 奇米成人av国产一区二区三区| 欧美国产日韩一区二区| 亚洲加勒比久久88色综合| 91精品视频专区| 国产亚洲精品久久久久久777| 久久久之久亚州精品露出| 中文字幕日韩专区| 一区二区三区久久精品| 久久精品99久久久久久久久| 福利二区91精品bt7086| 久久精品男人天堂| 国产亚洲欧美另类中文| 欧美日韩ab片| 成人欧美一区二区三区黑人孕妇| yw.139尤物在线精品视频| 欧美成年人视频网站欧美| 久久精品国产一区二区三区| 亚洲美女久久久| 久久精品国产免费观看| 欧美一级在线亚洲天堂| 俺去啦;欧美日韩| 欧美日韩精品中文字幕| 欧美黄色成人网| 久久久久久国产精品美女| 国产成人亚洲综合| 精品日韩美女的视频高清| 国产精品国产三级国产专播精品人| 91九色国产在线| 在线a欧美视频| 日韩电视剧在线观看免费网站| 精品国产区一区二区三区在线观看| 中文字幕不卡在线视频极品| 久久久久久久999| 97在线视频国产| 国产精品久久久久久久7电影| 欧美另类69精品久久久久9999| 一二美女精品欧洲| 久久久久久18| 国产精品户外野外| 狠狠久久五月精品中文字幕| 91九色国产在线| 国产主播在线一区| 欧美丝袜一区二区| 久久免费国产视频| 亚洲电影在线观看| 精品成人69xx.xyz| 日韩av综合网| 青青久久av北条麻妃海外网| 亚洲国产黄色片| 欧美午夜视频在线观看| 国产日韩av在线播放| 亚洲精品久久久久久下一站| 亚洲a成v人在线观看| 精品视频在线导航| 欧美另类99xxxxx| 精品久久在线播放| 亚洲精品91美女久久久久久久| 在线性视频日韩欧美| 亚洲成人精品在线| 日本久久久久久久| 国产亚洲综合久久| 欧美日韩中国免费专区在线看| 亚洲国产一区自拍| 欧美成人性色生活仑片| 国产99视频精品免视看7| 日韩欧美亚洲成人| 亚洲精品美女在线观看| 精品福利视频导航| 亚洲欧美另类中文字幕| 国产一区二区三区直播精品电影| 久久手机免费视频| 亚洲一区二区中文字幕| 欧美肥婆姓交大片| 久久成人精品电影| 97在线观看视频国产| 欧美成人激情图片网| 成人性生交大片免费看视频直播| 精品久久久久久久久久久| 亚洲精品www| 91精品视频免费看| 成人国内精品久久久久一区| 夜夜嗨av色一区二区不卡| 亚洲国产精品va在线看黑人| 美日韩精品免费观看视频| 欧美色播在线播放| 亚洲欧洲日韩国产| 日韩电影中文字幕| 91精品综合视频| 精品夜色国产国偷在线| 色偷偷888欧美精品久久久| 日本精品久久电影| 最新国产成人av网站网址麻豆| 欧美在线观看网址综合| 亚洲一区二区三区在线免费观看| 久久久精品2019中文字幕神马| 欧美日韩午夜激情| 国产欧美一区二区三区久久人妖| 中日韩美女免费视频网址在线观看| 国产一区二区三区中文| 在线播放日韩专区| 国产精品自拍视频| 欧美色另类天堂2015| 国产美女精品免费电影| 亚洲欧美视频在线|