Skip to content

Instantly share code, notes, and snippets.

@ustreamer-01647
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ustreamer-01647/8e5510c925893826bf27 to your computer and use it in GitHub Desktop.
Save ustreamer-01647/8e5510c925893826bf27 to your computer and use it in GitHub Desktop.
codeiq863チケットゴブル社の旅行プランを作れ!
<?php
/**
* https://codeiq.jp/ace/yuki_hiroshi/q863 チケットゴブル社の旅行プランを作れ!
*/
// -------------------------------------------------------
// 設定
// 入力データのエンコーディング
define("INDATA_ENCODING", "SJIS");
// 内部データのエンコーディング
define("INSIDEDATA_ENCODING", "UTF-8");
// 入力ファイル名
define("INFILENAME", "tickets.txt");
// 改行コード
define("KAIGYO", "\r\n");
// 空白.出力整形に使う
define("WHITESPACE", " ");
// -------------------------------------------------------
// プロセス開始
// データ入力
$indata = mb_convert_encoding(file_get_contents(INFILENAME), INSIDEDATA_ENCODING, INDATA_ENCODING);
$data = explode(KAIGYO, trim($indata));
foreach ($data as $d) {
$tickets[] = new Ticket($d);
}
// 初期の並び順を後で使うかもしれないと思ったけれど,結局使わなかった.けどworkTicketsで作業する
$workTickets = $tickets;
// 同一日程チケットは1個に絞る
$cut["sameTerm"] = cutSameTerm();
putCutSameTerm($cut["sameTerm"]);
// 期間に収まるチケットがある場合,刈り取る.短期間チケットを優先し,余裕日数を増やす
$cut["canContain"] = cutCanContain();
putCutCanContain($cut["canContain"]);
// ソートする.添字の抜けを詰める
usort($workTickets, "Ticket::compare");
// 期間が重なるチケットを抽出する
$cut["crossGroup"] = getCrossGroup();
// 期間が重なるチケットについて,除去すべきチケットキー値を得る
$cut["cross"] = optimizeCrossGroups($cut["crossGroup"]);
putCrossGroup($cut["crossGroup"]);
cutCross($cut["cross"]);
// 結果表示
echo KAIGYO . "result" . KAIGYO;
usort($workTickets, "Ticket::compareCountry");
putTickets(array_merge($workTickets));
// -------------------------------------------------------
// 以上が全プロセス
// 以下クラス定義や関数
class Ticket {
// 一月が持つ最大日数.month/dayを認識してのUnix時間でも良かった
static $MAXDAYS = 31;
// プロパティ
private $properties = array();
/**
* getter
* http://qiita.com/mikakane/items/00c798964f7c2c122e7d#comment-0978375a35c172b48d29 PHPのGetter/Setterについて本気出して考えてみた - Qiita
* @param string $name 連想配列識別子
* @return type 当該プロパティ.ない場合はnull
*/
public function property($name) {//, $value = null) {
return isset($this->properties[$name]) ? $this->properties[$name] : null;
}
/**
* @param type $line チケット情報文字列
*/
function Ticket($line) {
// $line = "Afghanistan 4/17-4/18"
// 前後分割
$l = explode(" ", $line);
$this->properties["country"] = $l[0];
// 始点終点分割.4/17-4/18
$days = explode("-", $l[1]);
// 始点.4/17
$startday = explode("/", $days[0]);
$this->properties["start"] = $startday[0] * Ticket::$MAXDAYS + $startday[1];
// 終点.4/18
$endday = explode("/", $days[1]);
$this->properties["end"] = $endday[0] * Ticket::$MAXDAYS + $endday[1];
}
/**
* チケット期間に内包できるか
* @param Ticket $ticket
* @return bool 内包できる場合true
*/
function canContain($ticket) {
$start = $ticket->property("start");
$end = $ticket->property("end");
return ($this->properties["start"] <= $start && $end <= $this->properties["end"]) ?
true : false;
}
/**
* 日程が重なるか
* @param Ticket $ticket
* @return bool 日程が重なる場合true
*/
function isCross($ticket) {
$start = $ticket->properties["start"];
$end = $ticket->properties["end"];
return (($this->properties["start"] <= $start && $start <= $this->properties["end"]) || ($this->properties["start"] <= $end && $end <= $this->properties["end"])) ?
true : false;
}
/**
* 日程が同一であるか
* @param Ticket $ticket
* @return bool 日程が同一ならtrue
*/
function isSameTerm($ticket) {
$isSameStart = $ticket->properties["start"] === $this->properties["start"];
$isSameEnd = $ticket->properties["end"] === $this->properties["end"];
return $isSameStart && $isSameEnd;
}
/**
* チケット日程文字列
* @return string チケット日程文字列
*/
function getTerm() {
// 4/17-4/18
$startAmari = $this->properties["start"] % Ticket::$MAXDAYS;
if ($startAmari === 0) {
// 割り切れる場合,月は1を引く.日はMAXDAYS
$term = (int) ($this->properties["start"] / Ticket::$MAXDAYS) - 1 . "/" . Ticket::$MAXDAYS . "-";
} else {
$term = (int) ($this->properties["start"] / Ticket::$MAXDAYS) . "/" . $startAmari . "-";
}
$endAmari = $this->properties["end"] % Ticket::$MAXDAYS;
if ($endAmari === 0) {
$term .= (int) ($this->properties["end"] / Ticket::$MAXDAYS) - 1 . "/" . Ticket::$MAXDAYS;
} else {
$term .= (int) ($this->properties["end"] / Ticket::$MAXDAYS) . "/" . $endAmari;
}
return $term;
}
/**
* チケット情報文字列.Afghanistan 4/17-4/18
* @return string チケット情報文字列
*/
function __toString() {
// 確認
// Afghanistan 141-142
//return $this->properties["country"] . " " . $this->properties["start"] . "-" . $this->properties["end"];
// Afghanistan 4/17-4/18
return $this->properties["country"] . " " . $this->getTerm();
}
/**
* usort用関数
* http://www.php.net/manual/ja/function.usort.php usort — ユーザー定義の比較関数を使用して、配列を値でソートする
* @param Ticket $a
* @param Ticket $b
*/
static function compare($a, $b) {
return ($a->property("start") > $b->property("start") );
}
/**
* usort用関数
* @param Ticket $a
* @param Ticket $b
* @return type
*/
static function compareCountry($a, $b){
return ($a->property("country") > $b->property("country") );
}
/**
* チケット期日を拡げる
* @param Ticket $ticket
*/
function extendTerm($ticket) {
$this->properties["start"] = min($this->properties["start"], $ticket->property("start"));
$this->properties["end"] = max($this->properties["end"], $ticket->property("end"));
}
}
/**
* 同一期間チケット情報を出力する
* @global Ticket $tickets
* @param type $info 同一期間チケット情報
*/
function putCutSameTerm($info) {
$outdata = KAIGYO . __FUNCTION__ . KAIGYO;
$outdata .= count($info) . "個" . KAIGYO;
global $tickets;
foreach ($info as $term => $i) {
$outdata .= $term . KAIGYO;
foreach ($i as $value) {
$outdata .= WHITESPACE . $value . ":" . $tickets[$value]->property("country") . KAIGYO;
}
}
$outdata .= KAIGYO;
echo $outdata;
}
/**
* 別チケットを包含できるために除去したチケット情報を出力する
* @global Ticket $tickets
* @param type $info
*/
function putCutCanContain($info) {
$outdata = KAIGYO . __FUNCTION__ . KAIGYO;
$outdata .=count($info) . "個" . KAIGYO;
global $tickets;
foreach ($info as $key => $i) {
$outdata .= $key . ":" . $tickets[$key] . KAIGYO;
foreach ($i as $value) {
$outdata .=WHITESPACE . $value . ":" . $tickets[$value] . KAIGYO;
}
}
$outdata .=KAIGYO;
echo $outdata;
}
/**
* チケット期間が同一である場合,1個だけにする
* @global Ticket $workTickets
*/
function cutSameTerm() {
global $workTickets;
foreach ($workTickets as $key1 => $t1) {
foreach ($workTickets as $key2 => $t2) {
// 同じチケットならば比べない
if ($key1 === $key2) {
continue;
}
if ($t1->isSameTerm($t2)) {
// 全パターン調べるため,ループ外側の$key1だけ登録する
$cut[$t1->getTerm()][] = $key1;
}
}
}
foreach ($cut as $term) {
$c = count($term);
for ($i = 1; $i < $c; $i++) {
unset($workTickets[$term[$i]]);
}
}
return $cut;
}
/**
* チケット期間中に別チケットが収まる場合,これを刈り取る
* @global Ticket $workTickets
*/
function cutCanContain() {
global $workTickets;
foreach ($workTickets as $key1 => $t1) {
foreach ($workTickets as $key2 => $t2) {
// 同一チケットでは比べない
if ($key1 === $key2) {
continue;
}
if ($t1->canContain($t2) === true) {
$cut[$key1][] = $key2;
}
}
}
foreach ($cut as $key => $value) {
unset($workTickets[$key]);
}
return $cut;
}
/**
*
* @global Ticket $workTickets
*/
function getCrossGroup() {
$crossGroup = array();
global $workTickets;
$c = count($workTickets);
for ($i = 0; $i < $c; $i++) {
$tempTicket = clone $workTickets[$i];
// 重複するチケットキー値
$crossKeys = array($i);
for ($j = 0; $j < $c; $j++) {
if ($i === $j) {
continue;
}
if ($tempTicket->isCross($workTickets[$j])) {
// チケット期間拡張
$tempTicket->extendTerm($workTickets[$j]);
$crossKeys[] = $j;
}
}
// tempTicketが変化した場合,期間が異なる
if ($tempTicket->getTerm() !== $workTickets[$i]->getTerm()) {
$crossGroup[$tempTicket->getTerm()] = $crossKeys;
// 重複部分をスキップする
$i = end($crossKeys);
}
}
return $crossGroup;
}
/**
*
* @global Ticaa $workTickets
* @param type $info
*/
function putCrossGroup($info) {
$outdata = __FUNCTION__ . KAIGYO;
$outdata .= count($info) . "個" . KAIGYO;
global $workTickets;
foreach ($info as $term => $i) {
$outdata.= $term . KAIGYO;
foreach ($i as $value) {
$outdata .= WHITESPACE . $workTickets[$value] . KAIGYO;
}
}
$outdata.=KAIGYO;
echo $outdata;
}
/**
* 期間が重なるチケットについて,除去すべきチケットキー値を得る
* @param type $info 除去すべきチケットキー値配列
*/
function optimizeCrossGroups($info) {
$cut = array();
foreach ($info as $i) {
$cut = array_merge($cut, optimizeCrossGroup($i));
}
return $cut;
}
/**
* 一定期間内にある複数のチケットについて,重なりがなくなるような,除去すべきチケットキー値を得る
* optimizeCrossGroupsから呼ばれる
* @global Ticket $workTickets
* @param type $info 重なりがあるチケットキー値配列
* @return type 除去すべきチケットキー値配列
*/
function optimizeCrossGroup($info) {
$c = count($info);
if ($c < 2) {
echo "error: " . __FUNCTION__ . KAIGYO;
print_r($info);
exit(1);
}
global $workTickets;
$cut = array();
switch ($c) {
case 2:
$cut[] = $info[1];
break;
case 3:
$cut[] = $info[1];
if ($workTickets[$info[0]]->isCross($workTickets[$info[2]])) {
$cut[] = $info[2];
}
break;
case 4:
$cut[] = $info[1];
$cut[] = $info[2];
if ($workTickets[$info[0]]->isCross($workTickets[$info[3]])) {
$cut[] = $info[2];
}
break;
case 5:
$cut[] = $info[1];
$cut[] = $info[3];
unset($info[1]);
unset($info[3]);
if ($workTickets[$info[0]]->isCross($workTickets[$info[2]]) || $workTickets[$info[4]]->isCross($workTickets[$info[2]])) {
$cut[] = $info[2];
if ($workTickets[$info[0]]->isCross($workTickets[$info[4]])) {
$cut[] = $info[4];
}
}
break;
default :
echo "error: " . __FUNCTION__ . KAIGYO;
echo '$info > 5のようです.プログラムを改善しましょう' . KAIGYO;
print_r($info);
exit(1);
}
return $cut;
}
/**
* optimizeCrossGroupsが挙げたチケットを除去する
* @global Ticket $workTickets
* @param type $crossInfo
*/
function cutCross($crossInfo) {
global $workTickets;
foreach ($crossInfo as $i) {
unset($workTickets[$i]);
}
}
/**
* 使用するチケット
* @param Ticket $tickets
*/
function putTickets($tickets) {
$outdata = __FUNCTION__ . KAIGYO;
$outdata .= count($tickets) . " ";
foreach ($tickets as $t) {
$outdata .= $t->property("country") ." ";
}
$outdata .= KAIGYO;
echo $outdata;
}
/**
* 同一期間絞り込みと包含関係絞り込みが済んだデータと,
* 期間が重なるチケットを手作業で除去したデータをつなげた.
* optimizeCrossGroups()の結果と突き合わせるため,ソートする.
* 一致した.2014年5月3日8時52分
*/
function test() {
$data = <<< EOT
Kiribati 1/3-1/5
Oman 2/13-2/16
Finland 2/18-2/19
Denmark 2/22-2/24
Burundi 3/6-3/8
Germany 3/17-3/21
Tokelau 3/28-3/29
Afghanistan 4/17-4/18
Libya 4/19-4/21
Portugal 5/27-5/31
Antarctica 6/3-6/5
Rwanda 6/6-6/7
Narnia 6/8-6/9
Kyrgyzstan 6/13-6/14
Slovakia 6/16-6/17
Cyprus 6/27-6/28
Samoa 7/1-7/2
Turkey 7/11-7/12
Nigeria 7/23-7/25
Sweden 8/23-8/24
Slovenia 9/17-9/19
Malawi 9/20-9/21
Canada 9/26-9/27
Uganda 10/6-10/9
Namibia 10/10-10/12
Eritrea 10/15-10/17
Maldives 10/31-11/5
Fiji 11/19-11/20
Botswana 11/23-11/24
Chad 12/1-12/3
Egypt 12/5-12/6
Sudan 1/8-1/10
China 1/14-1/18
Tajikistan 1/20-1/23
Lesotho 1/29-2/3
Austria 2/7-2/8
Georgia 2/29-3/2
Liechtenstein 3/30-4/2
Macao 4/3-4/10
Azerbaijan 4/11-4/13
Niger 4/28-5/5
Norway 5/8-5/9
Angola 5/18-5/19
Serbia 6/20-6/24
Romania 7/5-7/7
Kuwait 7/14-7/18
Martinique 7/28-7/29
Ethiopia 8/1-8/6
Montenegro 8/9-8/11
Seychelles 8/12-8/17
Poland 8/27-8/28
Switzerland 8/31-9/4
Barbados 9/5-9/7
Belarus 9/8-9/15
Ukraine 9/28-9/29
Somalia 10/22-10/27
Ghana 11/7-11/9
Togo 11/16-11/17
Greece 11/27-11/28
Ecuador 12/7-12/8
Nauru 12/15-12/19
Guadeloupe 12/20-12/24
EOT;
foreach (explode(KAIGYO, trim($data)) as $d) {
$tickets[] = new Ticket($d);
}
usort($tickets, "Ticket::compare");
putTickets($tickets);
}
putCutSameTerm
8個
12/5-12/6
42:Egypt
75:Jordan
11/19-11/20
46:Fiji
132:Senegal
1/20-1/24
64:Haiti
65:Hungary
2/6-2/12
72:Italy
81:Latvia
7/14-7/18
79:Kuwait
84:Liberia
5/6-5/8
102:Mongolia
111:Nepal
7/23-7/25
115:Nigeria
135:Singapore
6/24-6/29
125:Pitcairn
159:Yemen
putCutCanContain
64個
1:Albania 9/25-10/2
29:Canada 9/26-9/27
50:Gambia 9/25-9/28
113:Nicaragua 9/29-10/2
155:Ukraine 9/28-9/29
2:Algeria 11/23-11/25
23:Botswana 11/23-11/24
3:Andorra 8/22-8/27
95:Malta 8/23-8/25
143:Sweden 8/23-8/24
8:Armenia 5/18-5/21
4:Angola 5/18-5/19
9:Aruba 1/1-1/8
78:Kiribati 1/3-1/5
10:Australia 3/25-3/31
148:Tokelau 3/28-3/29
13:Bahamas 8/20-8/24
143:Sweden 8/23-8/24
14:Bahrain 7/26-7/31
96:Martinique 7/28-7/29
18:Belgium 6/8-6/10
109:Narnia 6/8-6/9
22:Bhutan 9/14-9/19
137:Slovenia 9/17-9/19
24:Brazil 7/10-7/13
151:Turkey 7/11-7/12
25:Bulgaria 2/15-2/22
47:Finland 2/18-2/19
106:Mozambique 2/18-2/21
27:Cambodia 3/16-3/22
52:Germany 3/17-3/21
28:Cameroon 12/3-12/9
41:Ecuador 12/7-12/8
42:Egypt 12/5-12/6
101:Monaco 12/4-12/7
123:Peru 12/5-12/7
31:Chile 5/7-5/13
117:Norway 5/8-5/9
149:Tonga 5/8-5/10
33:Colombia 3/2-3/5
5:Anguilla 3/2-3/3
34:Comoros 8/26-8/28
126:Poland 8/27-8/28
35:Congo 4/2-4/9
76:Kazakhstan 4/2-4/8
36:Cuba 1/10-1/17
82:Lebanon 1/10-1/14
40:Dominica 12/19-12/24
58:Guadeloupe 12/20-12/24
44:Estonia 11/4-11/11
53:Ghana 11/7-11/9
48:France 6/29-7/3
131:Samoa 7/1-7/2
49:Gabon 3/27-4/3
86:Liechtenstein 3/30-4/2
148:Tokelau 3/28-3/29
50:Gambia 9/25-9/28
29:Canada 9/26-9/27
54:Gibraltar 7/10-7/15
24:Brazil 7/10-7/13
151:Turkey 7/11-7/12
57:Grenada 10/11-10/18
43:Eritrea 10/15-10/17
59:Guam 4/11-4/16
12:Azerbaijan 4/11-4/13
60:Guatemala 3/6-3/9
26:Burundi 3/6-3/8
62:Guinea 6/4-6/8
130:Rwanda 6/6-6/7
64:Haiti 1/20-1/24
145:Tajikistan 1/20-1/23
66:Iceland 7/25-8/1
14:Bahrain 7/26-7/31
96:Martinique 7/28-7/29
67:India 7/21-7/28
115:Nigeria 7/23-7/25
68:Indonesia 8/20-8/27
3:Andorra 8/22-8/27
13:Bahamas 8/20-8/24
95:Malta 8/23-8/25
143:Sweden 8/23-8/24
69:Iraq 9/12-9/18
61:Guernsey 9/13-9/16
71:Israel 6/11-6/18
80:Kyrgyzstan 6/13-6/14
119:Pakistan 6/11-6/16
120:Palau 6/11-6/14
136:Slovakia 6/16-6/17
72:Italy 2/6-2/12
11:Austria 2/7-2/8
87:Lithuania 5/2-5/8
56:Greenland 5/3-5/6
102:Mongolia 5/6-5/8
90:Madagascar 11/15-11/22
46:Fiji 11/19-11/20
147:Togo 11/16-11/17
94:Mali 9/17-9/24
91:Malawi 9/20-9/21
137:Slovenia 9/17-9/19
95:Malta 8/23-8/25
143:Sweden 8/23-8/24
97:Mauritania 10/13-10/20
43:Eritrea 10/15-10/17
99:Mayotte 10/24-10/29
70:Ireland 10/25-10/28
100:Mexico 2/24-3/2
51:Georgia 2/29-3/2
101:Monaco 12/4-12/7
42:Egypt 12/5-12/6
123:Peru 12/5-12/7
105:Morocco 6/26-6/29
37:Cyprus 6/27-6/28
106:Mozambique 2/18-2/21
47:Finland 2/18-2/19
107:Myanmar 11/29-12/3
30:Chad 12/1-12/3
116:Niue 5/14-5/21
4:Angola 5/18-5/19
8:Armenia 5/18-5/21
119:Pakistan 6/11-6/16
80:Kyrgyzstan 6/13-6/14
120:Palau 6/11-6/14
120:Palau 6/11-6/14
80:Kyrgyzstan 6/13-6/14
123:Peru 12/5-12/7
42:Egypt 12/5-12/6
125:Pitcairn 6/24-6/29
37:Cyprus 6/27-6/28
105:Morocco 6/26-6/29
128:Qatar 1/16-1/23
145:Tajikistan 1/20-1/23
139:Spain 9/24-9/29
29:Canada 9/26-9/27
50:Gambia 9/25-9/28
155:Ukraine 9/28-9/29
142:Swaziland 6/10-6/16
80:Kyrgyzstan 6/13-6/14
119:Pakistan 6/11-6/16
120:Palau 6/11-6/14
146:Thailand 6/27-6/30
37:Cyprus 6/27-6/28
149:Tonga 5/8-5/10
117:Norway 5/8-5/9
150:Tunisia 11/16-11/23
46:Fiji 11/19-11/20
147:Togo 11/16-11/17
152:Turkmenistan 11/28-11/30
141:Suriname 11/28-11/29
153:Tuvalu 3/15-3/22
27:Cambodia 3/16-3/22
52:Germany 3/17-3/21
156:Uruguay 7/1-7/6
131:Samoa 7/1-7/2
157:Uzbekistan 2/26-3/4
5:Anguilla 3/2-3/3
51:Georgia 2/29-3/2
160:Zambia 1/27-2/3
83:Lesotho 1/29-2/3
161:Zimbabwe 10/29-11/5
93:Maldives 10/31-11/5
putCrossGroup
20個
1/8-1/18
Sudan 1/8-1/10
Lebanon 1/10-1/14
China 1/14-1/18
1/20-1/25
Tajikistan 1/20-1/23
Jamaica 1/23-1/25
1/29-2/8
Lesotho 1/29-2/3
Jersey 1/31-2/6
Argentina 2/2-2/7
Austria 2/7-2/8
2/29-3/3
Georgia 2/29-3/2
Anguilla 3/2-3/3
3/30-4/13
Liechtenstein 3/30-4/2
Kazakhstan 4/2-4/8
Macao 4/3-4/10
Philippines 4/6-4/11
Azerbaijan 4/11-4/13
4/28-5/9
Niger 4/28-5/5
Greenland 5/3-5/6
Mongolia 5/6-5/8
Norway 5/8-5/9
5/18-5/24
Angola 5/18-5/19
Djibouti 5/19-5/24
6/20-6/26
Serbia 6/20-6/24
Bangladesh 6/22-6/26
7/5-7/10
Romania 7/5-7/7
Belize 7/6-7/10
7/14-7/20
Kuwait 7/14-7/18
Panama 7/18-7/20
7/28-8/11
Martinique 7/28-7/29
Kenya 7/29-8/4
Ethiopia 8/1-8/6
Benin 8/6-8/10
Montenegro 8/9-8/11
8/12-8/21
Seychelles 8/12-8/17
Vanuatu 8/15-8/21
8/27-9/7
Poland 8/27-8/28
Luxembourg 8/28-8/31
Switzerland 8/31-9/4
Bermuda 9/3-9/6
Barbados 9/5-9/7
9/8-9/16
Belarus 9/8-9/15
Guernsey 9/13-9/16
9/28-10/2
Ukraine 9/28-9/29
Nicaragua 9/29-10/2
10/22-10/30
Somalia 10/22-10/27
Ireland 10/25-10/28
Guyana 10/26-10/30
11/7-11/17
Ghana 11/7-11/9
Paraguay 11/9-11/15
Malaysia 11/10-11/16
Togo 11/16-11/17
11/27-11/29
Greece 11/27-11/28
Suriname 11/28-11/29
12/7-12/19
Ecuador 12/7-12/8
Netherlands 12/8-12/12
Montserrat 12/12-12/16
Nauru 12/15-12/19
12/20-12/28
Guadeloupe 12/20-12/24
Mauritius 12/21-12/28
result
putTickets
62個
Kiribati 1/3-1/5
Sudan 1/8-1/10
China 1/14-1/18
Tajikistan 1/20-1/23
Lesotho 1/29-2/3
Austria 2/7-2/8
Oman 2/13-2/16
Finland 2/18-2/19
Denmark 2/22-2/24
Georgia 2/29-3/2
Burundi 3/6-3/8
Germany 3/17-3/21
Tokelau 3/28-3/29
Liechtenstein 3/30-4/2
Macao 4/3-4/10
Azerbaijan 4/11-4/13
Afghanistan 4/17-4/18
Libya 4/19-4/21
Niger 4/28-5/5
Norway 5/8-5/9
Angola 5/18-5/19
Portugal 5/27-5/31
Antarctica 6/3-6/5
Rwanda 6/6-6/7
Narnia 6/8-6/9
Kyrgyzstan 6/13-6/14
Slovakia 6/16-6/17
Serbia 6/20-6/24
Cyprus 6/27-6/28
Samoa 7/1-7/2
Romania 7/5-7/7
Turkey 7/11-7/12
Kuwait 7/14-7/18
Nigeria 7/23-7/25
Martinique 7/28-7/29
Ethiopia 8/1-8/6
Montenegro 8/9-8/11
Seychelles 8/12-8/17
Sweden 8/23-8/24
Poland 8/27-8/28
Switzerland 8/31-9/4
Barbados 9/5-9/7
Belarus 9/8-9/15
Slovenia 9/17-9/19
Malawi 9/20-9/21
Canada 9/26-9/27
Ukraine 9/28-9/29
Uganda 10/6-10/9
Namibia 10/10-10/12
Eritrea 10/15-10/17
Somalia 10/22-10/27
Maldives 10/31-11/5
Ghana 11/7-11/9
Togo 11/16-11/17
Fiji 11/19-11/20
Botswana 11/23-11/24
Greece 11/27-11/28
Chad 12/1-12/3
Egypt 12/5-12/6
Ecuador 12/7-12/8
Nauru 12/15-12/19
Guadeloupe 12/20-12/24
62 Kiribati Sudan China Tajikistan Lesotho Austria Oman Finland Denmark Georgia Burundi Germany Tokelau Liechtenstein Macao Azerbaijan Afghanistan Libya Niger Norway Angola Portugal Antarctica Rwanda Narnia Kyrgyzstan Slovakia Serbia Cyprus Samoa Romania Turkey Kuwait Nigeria Martinique Ethiopia Montenegro Seychelles Sweden Poland Switzerland Barbados Belarus Slovenia Malawi Canada Ukraine Uganda Namibia Eritrea Somalia Maldives Ghana Togo Fiji Botswana Greece Chad Egypt Ecuador Nauru Guadeloupe
62 Afghanistan Angola Antarctica Austria Azerbaijan Barbados Belarus Botswana Burundi Canada Chad China Cyprus Denmark Ecuador Egypt Eritrea Ethiopia Fiji Finland Georgia Germany Ghana Greece Guadeloupe Kiribati Kuwait Kyrgyzstan Lesotho Libya Liechtenstein Macao Malawi Maldives Martinique Montenegro Namibia Narnia Nauru Niger Nigeria Norway Oman Poland Portugal Romania Rwanda Samoa Serbia Seychelles Slovakia Slovenia Somalia Sudan Sweden Switzerland Tajikistan Togo Tokelau Turkey Uganda Ukraine
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment