使用spatie/opening-hours
您可以建立一個描述企業營業時間的對象,您可以查詢該對象的open
或特定日期的營業時間或closed
,或用於顯示每天的時間。
由於 cmixin/business-time, spatie/opening-hours
可以直接在 Carbon 上使用,因此您可以直接在增強的日期物件上受益於開放時間功能。
透過傳入定期時間表和例外清單來建立一組開放時間。
// Add the use at the top of each file where you want to use the OpeningHours class:
use Spatie OpeningHours OpeningHours ;
$ openingHours = OpeningHours:: create ([
' monday ' => [ ' 09:00-12:00 ' , ' 13:00-18:00 ' ],
' tuesday ' => [ ' 09:00-12:00 ' , ' 13:00-18:00 ' ],
' wednesday ' => [ ' 09:00-12:00 ' ],
' thursday ' => [ ' 09:00-12:00 ' , ' 13:00-18:00 ' ],
' friday ' => [ ' 09:00-12:00 ' , ' 13:00-20:00 ' ],
' saturday ' => [ ' 09:00-12:00 ' , ' 13:00-16:00 ' ],
' sunday ' => [],
' exceptions ' => [
' 2016-11-11 ' => [ ' 09:00-12:00 ' ],
' 2016-12-25 ' => [],
' 01-01 ' => [], // Recurring on each 1st of January
' 12-25 ' => [ ' 09:00-12:00 ' ], // Recurring on each 25th of December
],
]);
// This will allow you to display things like:
$ now = new DateTime ( ' now ' );
$ range = $ openingHours -> currentOpenRange ( $ now );
if ( $ range ) {
echo " It's open since " . $ range -> start (). "n" ;
echo " It will close at " . $ range -> end (). "n" ;
} else {
echo " It's closed since " . $ openingHours -> previousClose ( $ now )-> format ( ' l H:i ' ). "n" ;
echo " It will re-open at " . $ openingHours -> nextOpen ( $ now )-> format ( ' l H:i ' ). "n" ;
}
可以查詢一週中的某一天的對象,這將根據常規時間表傳回結果:
// Open on Mondays:
$ openingHours -> isOpenOn ( ' monday ' ); // true
// Closed on Sundays:
$ openingHours -> isOpenOn ( ' sunday ' ); // false
也可以查詢特定日期和時間:
// Closed because it's after hours:
$ openingHours -> isOpenAt ( new DateTime ( ' 2016-09-26 19:00:00 ' )); // false
// Closed because Christmas was set as an exception
$ openingHours -> isOpenOn ( ' 2016-12-25 ' ); // false
它還可以傳回一周或一天的營業時間數組:
// OpeningHoursForDay object for the regular schedule
$ openingHours -> forDay ( ' monday ' );
// OpeningHoursForDay[] for the regular schedule, keyed by day name
$ openingHours -> forWeek ();
// Array of day with same schedule for the regular schedule, keyed by day name, days combined by working hours
$ openingHours -> forWeekCombined ();
// OpeningHoursForDay object for a specific day
$ openingHours -> forDate ( new DateTime ( ' 2016-12-25 ' ));
// OpeningHoursForDay[] of all exceptions, keyed by date
$ openingHours -> exceptions ();
在建造時,您可以為跨天的溢出時間設定一個標誌。例如,對於週五和週六營業至凌晨 3 點的夜總會:
$ openingHours = Spatie OpeningHours OpeningHours:: create ([
' overflow ' => true ,
' friday ' => [ ' 20:00-03:00 ' ],
' saturday ' => [ ' 20:00-03:00 ' ],
], null );
這允許 API 進一步根據前一天的資料檢查開放時間是否在其時間範圍內開放。
您可以在定義中新增資料然後檢索它們:
$ openingHours = OpeningHours:: create ([
' monday ' => [
' data ' => ' Typical Monday ' ,
' 09:00-12:00 ' ,
' 13:00-18:00 ' ,
],
' tuesday ' => [
' 09:00-12:00 ' ,
' 13:00-18:00 ' ,
[
' 19:00-21:00 ' ,
' data ' => ' Extra on Tuesday evening ' ,
],
],
' exceptions ' => [
' 2016-12-25 ' => [
' data ' => ' Closed for Christmas ' ,
],
],
]);
echo $ openingHours -> forDay ( ' monday ' )-> data ; // Typical Monday
echo $ openingHours -> forDate ( new DateTime ( ' 2016-12-25 ' ))-> data ; // Closed for Christmas
echo $ openingHours -> forDay ( ' tuesday ' )[ 2 ]-> data ; // Extra on Tuesday evening
在上面的範例中,資料是字串,但它可以是任何類型的值。因此,您可以在數組中嵌入多個屬性。
為了結構方便,資料-小時對可以是完全關聯的數組,因此上面的範例嚴格等同於以下內容:
$ openingHours = OpeningHours:: create ([
' monday ' => [
' hours ' => [
' 09:00-12:00 ' ,
' 13:00-18:00 ' ,
],
' data ' => ' Typical Monday ' ,
],
' tuesday ' => [
[ ' hours ' => ' 09:00-12:00 ' ],
[ ' hours ' => ' 13:00-18:00 ' ],
[ ' hours ' => ' 19:00-21:00 ' , ' data ' => ' Extra on Tuesday evening ' ],
],
// Open by night from Wednesday 22h to Thursday 7h:
' wednesday ' => [ ' 22:00-24:00 ' ], // use the special "24:00" to reach midnight included
' thursday ' => [ ' 00:00-07:00 ' ],
' exceptions ' => [
' 2016-12-25 ' => [
' hours ' => [],
' data ' => ' Closed for Christmas ' ,
],
],
]);
您可以使用分隔to
一次指定多天、一週或例外情況:
$ openingHours = OpeningHours:: create ([
' monday to friday ' => [ ' 09:00-19:00 ' ],
' saturday to sunday ' => [],
' exceptions ' => [
// Every year
' 12-24 to 12-26 ' => [
' hours ' => [],
' data ' => ' Holidays ' ,
],
// Only happening in 2024
' 2024-06-25 to 2024-07-01 ' => [
' hours ' => [],
' data ' => ' Closed for works ' ,
],
],
]);
最後一個結構工具是過濾器,它允許您傳遞以日期作為參數並傳回給定日期的設定的閉包(或可呼叫函數/方法引用)。
$ openingHours = OpeningHours:: create ([
' monday ' => [
' 09:00-12:00 ' ,
],
' filters ' => [
function ( $ date ) {
$ year = intval ( $ date -> format ( ' Y ' ));
$ easterMonday = new DateTimeImmutable ( ' 2018-03-21 + ' .( easter_days ( $ year ) + 1 ). ' days ' );
if ( $ date -> format ( ' m-d ' ) === $ easterMonday -> format ( ' m-d ' )) {
return []; // Closed on Easter Monday
// Any valid exception-array can be returned here (range of hours, with or without data)
}
// Else the filter does not apply to the given date
},
],
]);
如果在"exceptions"
屬性中找到可呼叫對象,它將自動添加到過濾器中,以便您可以在例外數組中混合過濾器和異常。傳回非空值的第一個過濾器將優先於下一個過濾器,並且過濾器數組優先於異常數組內的過濾器。
警告:我們將為需要檢索開放時間的每個日期循環使用所有過濾器,並且既不能謂詞也不能緩存結果(可以是隨機函數),因此您必須小心過濾器、過濾器太多或過濾器內的處理時間過長可能會對效能產生重大影響。
它也可以傳回給定DateTime
的下一個開啟或關閉DateTime
。
// The next open datetime is tomorrow morning, because we’re closed on 25th of December.
$ nextOpen = $ openingHours -> nextOpen ( new DateTime ( ' 2016-12-25 10:00:00 ' )); // 2016-12-26 09:00:00
// The next open datetime is this afternoon, after the lunch break.
$ nextOpen = $ openingHours -> nextOpen ( new DateTime ( ' 2016-12-24 11:00:00 ' )); // 2016-12-24 13:00:00
// The next close datetime is at noon.
$ nextClose = $ openingHours -> nextClose ( new DateTime ( ' 2016-12-24 10:00:00 ' )); // 2016-12-24 12:00:00
// The next close datetime is tomorrow at noon, because we’re closed on 25th of December.
$ nextClose = $ openingHours -> nextClose ( new DateTime ( ' 2016-12-25 15:00:00 ' )); // 2016-12-26 12:00:00
閱讀完整 API 的使用部分。
Spatie 是一家位於比利時安特衛普的網頁設計公司。您可以在我們的網站上找到所有開源專案的概述。
我們投入了大量資源來創建一流的開源套件。您可以透過購買我們的一款付費產品來支持我們。
我們非常感謝您從家鄉寄給我們一張明信片,並註明您正在使用我們的哪種套餐。您可以在我們的聯絡頁面上找到我們的地址。我們在虛擬明信片牆上發布所有收到的明信片。
您可以透過 Composer 安裝該軟體包:
composer require spatie/opening-hours
該套件只能透過OpeningHours
類別使用。整個過程中也使用了三個值物件類, Time
(表示單一時間)、 TimeRange
(表示具有開始和結束的時間段)和openingHoursForDay
(表示一組不能重疊的TimeRange
)。
SpatieOpeningHoursOpeningHours
OpeningHours::create(array $data, $timezone = null, $toutputTimezone = null): SpatieOpeningHoursOpeningHours
靜態工廠方法來填滿設定的開放時間。
$ openingHours = OpeningHours:: create ([
' monday ' => [ ' 09:00-12:00 ' , ' 13:00-18:00 ' ],
// ...
]);
如果未指定時區, OpeningHours
將假定您始終傳遞時區已與您的日程安排相符的DateTime
物件。
如果您傳遞$timezone
作為第二個參數或透過數組鍵'timezone'
(它可以是DateTimeZone
物件或string
),則傳遞的日期將在每個方法的開頭轉換為該時區,然後如果該方法傳回日期物件(例如nextOpen
、 nextClose
、 previousOpen
、 previousClose
、 currentOpenRangeStart
或currentOpenRangeEnd
),然後在輸出之前將其轉換回原始時區,以便該物件可以反映使用者本地時間中的某個時刻,而OpeningHours
可以堅持自己的業務時區。
或者,您也可以指定輸入和輸出時區(使用第二個和第三個參數)或使用陣列:
$ openingHours = OpeningHours:: create ([
' monday ' => [ ' 09:00-12:00 ' , ' 13:00-18:00 ' ],
' timezone ' => [
' input ' => ' America/New_York ' ,
' output ' => ' Europe/Oslo ' ,
],
]);
OpeningHours::mergeOverlappingRanges(array $schedule) : array
為了安全起見,建立具有重疊範圍的OpeningHours
物件將引發異常,除非您在營業時間數組定義中明確傳遞'overflow' => true,
。您也可以明確合併它們。
$ ranges = [
' monday ' => [ ' 08:00-11:00 ' , ' 10:00-12:00 ' ],
];
$ mergedRanges = OpeningHours:: mergeOverlappingRanges ( $ ranges ); // Monday becomes ['08:00-12:00']
OpeningHours:: create ( $ mergedRanges );
// Or use the following shortcut to create from ranges that possibly overlap:
OpeningHours:: createAndMergeOverlappingRanges ( $ ranges );
並非所有日期都是強制性的,如果缺少一天,它將被設定為關閉。
OpeningHours::fill(array $data): SpatieOpeningHoursOpeningHours
與create
相同,但非靜態。
$ openingHours = ( new OpeningHours )-> fill ([
' monday ' => [ ' 09:00-12:00 ' , ' 13:00-18:00 ' ],
// ...
]);
OpeningHours::forWeek(): SpatieOpeningHoursOpeningHoursForDay[]
傳回一週的OpeningHoursForDay
物件陣列。
$ openingHours -> forWeek ();
OpeningHours::forWeekCombined(): array
傳回天數數組。數組鍵是具有相同工作時間的第一天,數組值是具有相同工作時間和OpeningHoursForDay
物件的日期。
$ openingHours -> forWeekCombined ();
OpeningHours::forWeekConsecutiveDays(): array
傳回串聯日期的數組,相鄰日期具有相同的小時數。數組鍵是具有相同工作時間的第一天,數組值是具有相同工作時間和OpeningHoursForDay
物件的日期。
警告:無論初始資料中的日期順序如何,都將考慮從週一到週日的連續天而不循環(週一不連續到週日)。
$ openingHours -> forWeekConsecutiveDays ();
OpeningHours::forDay(string $day): SpatieOpeningHoursOpeningHoursForDay
傳回常規日期的OpeningHoursForDay
物件。日期是英文日期名稱的小寫字串。
$ openingHours -> forDay ( ' monday ' );
OpeningHours::forDate(DateTimeInterface $dateTime): SpatieOpeningHoursOpeningHoursForDay
傳回特定日期的OpeningHoursForDay
物件。它會尋找當天的例外情況,否則會根據正常時間表返回開放時間。
$ openingHours -> forDate ( new DateTime ( ' 2016-12-25 ' ));
OpeningHours::exceptions(): SpatieOpeningHoursOpeningHoursForDay[]
傳回異常的所有OpeningHoursForDay
物件的數組,以Ymd
日期字串為鍵。
$ openingHours -> exceptions ();
OpeningHours::isOpenOn(string $day): bool
檢查企業是否以正常時間表營業(至少包含 1 個營業時間範圍)。
$ openingHours -> isOpenOn ( ' saturday ' );
如果給定的字串是日期,它將檢查其是否開放(至少包含 1 個開放時間範圍),同時考慮常規日程安排和可能的例外情況。
$ openingHours -> isOpenOn ( ' 2020-09-03 ' );
$ openingHours -> isOpenOn ( ' 09-03 ' ); // If year is omitted, current year is used instead
OpeningHours::isClosedOn(string $day): bool
檢查營業日是否依正常時間表休息。
$ openingHours -> isClosedOn ( ' sunday ' );
OpeningHours::isOpenAt(DateTimeInterface $dateTime): bool
檢查企業是否在特定日期、特定時間營業。
$ openingHours -> isOpenAt ( new DateTime ( ' 2016-26-09 20:00 ' ));
OpeningHours::isClosedAt(DateTimeInterface $dateTime): bool
檢查企業是否在特定日期、特定時間關閉。
$ openingHours -> isClosedAt ( new DateTime ( ' 2016-26-09 20:00 ' ));
OpeningHours::isOpen(): bool
檢查該企業現在是否營業。
$ openingHours -> isOpen ();
OpeningHours::isClosed(): bool
檢查該企業現在是否關閉。
$ openingHours -> isClosed ();
OpeningHours::isAlwaysOpen(): bool
檢查企業是否 24/7 營業,沒有例外,也沒有過濾器。
if ( $ openingHours -> isAlwaysOpen ()) {
echo ' This business is open all day long every day. ' ;
}
OpeningHours::isAlwaysClosed(): bool
檢查該企業是否從未營業、沒有例外且沒有過濾器。
OpeningHours
接受空數組或列表,每個工作日都為空,沒有任何偏見。
如果它在您的網域中不是有效狀態,您應該使用此方法引發異常或顯示錯誤。
if ( $ openingHours -> isAlwaysClosed ()) {
throw new RuntimeException ( ' Opening hours missing ' );
}
OpeningHours::nextOpen
OpeningHours::nextOpen(
?DateTimeInterface $ dateTime = null ,
?DateTimeInterface $ searchUntil = null ,
?DateTimeInterface $ cap = null ,
) : DateTimeInterface`
傳回給定DateTime
( $dateTime
或從現在開始,如果此參數為空或省略)的下一個開啟DateTime
。
如果傳遞DateTimeImmutable
對象,則傳回DateTimeImmutable
對象。
將$searchUntil
設定為一個日期,如果在此時刻之前找不到開放時間,則會引發異常。
將$cap
設定為日期,以便如果在此之前找不到開放時間,則傳回$cap
。
$ openingHours -> nextOpen ( new DateTime ( ' 2016-12-24 11:00:00 ' ));
OpeningHours::nextClose
OpeningHours::nextClose(
?DateTimeInterface $ dateTime = null ,
?DateTimeInterface $ searchUntil = null ,
?DateTimeInterface $ cap = null ,
) : DateTimeInterface`
傳回給定DateTime
( $dateTime
或從現在開始,如果此參數為空或省略)的下一個關閉DateTime
。
如果傳遞DateTimeImmutable
對象,則傳回DateTimeImmutable
對象。
將$searchUntil
設定為日期,如果在此時刻之前找不到關閉時間,則會引發異常。
將$cap
設定為日期,以便如果在此之前找不到關閉時間,則傳回$cap
。
如果計劃始終打開或始終關閉,則不會發現任何狀態更改,因此nextOpen
(以及previousOpen
、 nextClose
和previousClose
)將拋出MaximumLimitExceeded
您可以捕獲它並做出相應反應,也可以使用isAlwaysOpen
/ isAlwaysClosed
方法來預測這樣的情況。
$ openingHours -> nextClose ( new DateTime ( ' 2016-12-24 11:00:00 ' ));
OpeningHours::previousOpen
OpeningHours::previousOpen(
?DateTimeInterface $ dateTime = null ,
?DateTimeInterface $ searchUntil = null ,
?DateTimeInterface $ cap = null ,
) : DateTimeInterface`
傳回給定DateTime
( $dateTime
或從現在開始,如果此參數為空或省略)的上一個開啟DateTime
。
如果傳遞DateTimeImmutable
對象,則傳回DateTimeImmutable
對象。
將$searchUntil
設定為日期,如果在此時間之後找不到開放時間,則會引發異常。
將$cap
設定為日期,以便如果在此時間之後找不到開放時間,則傳回$cap
。
$ openingHours -> previousOpen ( new DateTime ( ' 2016-12-24 11:00:00 ' ));
OpeningHours::previousClose
OpeningHours::previousClose(
?DateTimeInterface $ dateTime = null ,
?DateTimeInterface $ searchUntil = null ,
?DateTimeInterface $ cap = null ,
) : DateTimeInterface`
傳回給定DateTime
( $dateTime
或從現在開始,如果此參數為空或省略)的上一個關閉DateTime
。
如果傳遞DateTimeImmutable
對象,則傳回DateTimeImmutable
對象。
將$searchUntil
設定為日期,如果在此時間之後找不到關閉時間,則會拋出例外。
將$cap
設定為日期,以便如果在此時間之後找不到關閉時間,則傳回$cap
。
$ openingHours -> nextClose ( new DateTime ( ' 2016-12-24 11:00:00 ' ));
OpeningHours::diffInOpenHours(DateTimeInterface $startDate, DateTimeInterface $endDate) : float
傳回 2 個日期/時間之間的開放時間量(浮點數形式的小時數)。
$ openingHours -> diffInOpenHours ( new DateTime ( ' 2016-12-24 11:00:00 ' ), new DateTime ( ' 2016-12-24 16:34:25 ' ));
OpeningHours::diffInOpenMinutes(DateTimeInterface $startDate, DateTimeInterface $endDate) : float
傳回 2 個日期/時間之間的開放時間量(分鐘數,浮點數)。
OpeningHours::diffInOpenSeconds(DateTimeInterface $startDate, DateTimeInterface $endDate) : float
傳回 2 個日期/時間之間的開放時間量(浮點數形式的秒數)。
OpeningHours::diffInClosedHours(DateTimeInterface $startDate, DateTimeInterface $endDate) : float
傳回 2 個日期/時間之間的關閉時間(小時數,浮點數)。
$ openingHours -> diffInClosedHours ( new DateTime ( ' 2016-12-24 11:00:00 ' ), new DateTime ( ' 2016-12-24 16:34:25 ' ));
OpeningHours::diffInClosedMinutes(DateTimeInterface $startDate, DateTimeInterface $endDate) : float
傳回 2 個日期/時間之間的關閉時間(分鐘數,浮點數)。
OpeningHours::diffInClosedSeconds(DateTimeInterface $startDate, DateTimeInterface $endDate) : float
傳回 2 個日期/時間之間的關閉時間(秒數,浮點數)。
OpeningHours::currentOpenRange(DateTimeInterface $dateTime) : false | TimeRange
如果商家正在營業,則傳回目前營業範圍的SpatieOpeningHoursTimeRange
實例;如果商家已關閉,則傳回 false。
$ range = $ openingHours -> currentOpenRange ( new DateTime ( ' 2016-12-24 11:00:00 ' ));
if ( $ range ) {
echo " It's open since " . $ range -> start (). "n" ;
echo " It will close at " . $ range -> end (). "n" ;
} else {
echo " It's closed " ;
}
start()
和end()
方法傳回SpatieOpeningHoursTime
實例。從日期建立的Time
實例可以使用日期資訊進行格式化。這對於午夜溢出的範圍很有用:
$ period = $ openingHours -> currentOpenRange ( new DateTime ( ' 2016-12-24 11:00:00 ' ));
if ( $ period ) {
echo " It's open since " . $ period -> start ()-> format ( ' D Gh ' ). "n" ;
echo " It will close at " . $ period -> end ()-> format ( ' D Gh ' ). "n" ;
} else {
echo " It's closed " ;
}
OpeningHours::currentOpenRangeStart(DateTimeInterface $dateTime) : false | DateTime
如果商家正在營業,則傳回自商家開業以來的日期和時間的DateTime
實例;如果商家已關閉,則傳回 false。
注意:如果您使用夜間範圍,日期可以是前一天。
$ date = $ openingHours -> currentOpenRangeStart ( new DateTime ( ' 2016-12-24 11:00:00 ' ));
if ( $ date ) {
echo " It's open since " . $ date -> format ( ' H:i ' );
} else {
echo " It's closed " ;
}
OpeningHours::currentOpenRangeEnd(DateTimeInterface $dateTime) : false | DateTime
如果商家正在營業,則傳回營業時間之前的日期和時間的DateTime
實例;如果商家已關閉,則傳回 false。
注意:如果您使用夜間範圍,日期可以是第二天。
$ date = $ openingHours -> currentOpenRangeEnd ( new DateTime ( ' 2016-12-24 11:00:00 ' ));
if ( $ date ) {
echo " It will close at " . $ date -> format ( ' H:i ' );
} else {
echo " It's closed " ;
}
OpeningHours::createFromStructuredData(array|string $data, $timezone = null, $outputTimezone = null): SpatieOpeningHoursOpeningHours
使用 https://schema.org/OpeningHoursSpecification 陣列或 JSON 字串填入集合的靜態工廠方法。
dayOfWeek
支援日期名稱數組(Google 風格)或日期 URL 數組(官方 schema.org 規範)。
$ openingHours = OpeningHours:: createFromStructuredData ( ' [
{
"@type": "OpeningHoursSpecification",
"opens": "08:00",
"closes": "12:00",
"dayOfWeek": [
"https://schema.org/Monday",
"https://schema.org/Tuesday",
"https://schema.org/Wednesday",
"https://schema.org/Thursday",
"https://schema.org/Friday"
]
},
{
"@type": "OpeningHoursSpecification",
"opens": "14:00",
"closes": "18:00",
"dayOfWeek": [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday"
]
},
{
"@type": "OpeningHoursSpecification",
"opens": "00:00",
"closes": "00:00",
"validFrom": "2023-12-25",
"validThrough": "2023-12-25"
}
] ' );
OpeningHours::asStructuredData(strinf $format = 'H:i', string|DateTimeZone $timezone) : array
以數組形式傳回 OpeningHoursSpecification。
$ openingHours -> asStructuredData ();
$ openingHours -> asStructuredData ( ' H:i:s ' ); // Customize time format, could be 'h:i a', 'G:i', etc.
$ openingHours -> asStructuredData ( ' H:iP ' , ' -05:00 ' ); // Add a timezone
// Timezone can be numeric or string like "America/Toronto" or a DateTimeZone instance
// But be careful, the time is arbitrary applied on 1970-01-01, so it does not handle daylight
// saving time, meaning Europe/Paris is always +01:00 even in summer time.
SpatieOpeningHoursOpeningHoursForDay
該類別是唯讀的。它實作了ArrayAccess
、 Countable
和IteratorAggregate
因此您可以以類似陣列的方式處理TimeRange
清單。
SpatieOpeningHoursTimeRange
描述具有開始時間和結束時間的時間段的值物件。可以轉換為H:iH:i
格式的字串。
SpatieOpeningHoursTime
描述單一時間的值物件。可以轉換為H:i
格式的字串。
您可以使用 osm-opening-hours 將 OpenStreetMap 格式轉換為OpeningHours
物件(感謝 mgrundkoetter)
請參閱變更日誌以了解有關最近更改內容的更多資訊。
composer test
詳細資訊請參閱貢獻。
如果您發現有關安全的錯誤,請發送郵件至 [email protected],而不是使用問題追蹤器。
您可以自由使用這個軟體包,但如果它進入您的生產環境,我們非常感謝您從您的家鄉給我們寄一張明信片,註明您正在使用我們的哪個軟體包。
我們的地址是:Spatie, Kruikstraat 22, 2018 安特衛普, 比利時。
我們在公司網站上發布所有收到的明信片。
麻省理工學院許可證 (MIT)。請參閱許可證文件以獲取更多資訊。