2018-01-28 23:22:43 +11:00
|
|
|
//Integrated TL
|
2019-05-19 17:39:30 +10:00
|
|
|
function mixtl(acct_id, tlid, type, delc, voice) {
|
2018-01-28 23:22:43 +11:00
|
|
|
localStorage.removeItem("morelock")
|
|
|
|
localStorage.setItem("now", type);
|
|
|
|
todo("Integrated TL Loading...(Local)");
|
2019-05-19 17:39:30 +10:00
|
|
|
//まずLocal
|
|
|
|
var domain = localStorage.getItem("domain_" + acct_id);
|
|
|
|
var at = localStorage.getItem("acct_" + acct_id + "_at");
|
|
|
|
var start = "https://" + domain + "/api/v1/timelines/public?local=true";
|
2018-01-28 23:22:43 +11:00
|
|
|
fetch(start, {
|
|
|
|
method: 'GET',
|
|
|
|
headers: {
|
|
|
|
'content-type': 'application/json',
|
|
|
|
'Authorization': 'Bearer ' + at
|
|
|
|
},
|
2019-05-19 17:39:30 +10:00
|
|
|
}).then(function (response) {
|
2019-10-31 02:30:26 +11:00
|
|
|
if (!response.ok) {
|
|
|
|
response.text().then(function(text) {
|
|
|
|
setLog(response.url, response.status, text);
|
|
|
|
});
|
|
|
|
}
|
2018-01-28 23:22:43 +11:00
|
|
|
return response.json();
|
2019-05-19 17:39:30 +10:00
|
|
|
}).catch(function (error) {
|
2018-01-28 23:22:43 +11:00
|
|
|
todo(error);
|
|
|
|
console.error(error);
|
2019-05-19 17:39:30 +10:00
|
|
|
}).then(function (jsonL) {
|
|
|
|
var start = "https://" + domain + "/api/v1/timelines/home";
|
|
|
|
fetch(start, {
|
|
|
|
method: 'GET',
|
|
|
|
headers: {
|
|
|
|
'content-type': 'application/json',
|
|
|
|
'Authorization': 'Bearer ' + at
|
|
|
|
},
|
|
|
|
}).then(function (response) {
|
2019-10-31 02:30:26 +11:00
|
|
|
if (!response.ok) {
|
|
|
|
response.text().then(function(text) {
|
|
|
|
setLog(response.url, response.status, text);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return response.json();
|
2019-05-19 17:39:30 +10:00
|
|
|
}).catch(function (error) {
|
|
|
|
todo(error);
|
|
|
|
console.error(error);
|
|
|
|
}).then(function (jsonH) {
|
|
|
|
var homearr = [];
|
|
|
|
var timeline = jsonL.concat(jsonH);
|
|
|
|
timeline.sort(function (a, b) {
|
|
|
|
if (date(a.created_at, "unix") >= date(b.created_at, "unix")) return -1;
|
|
|
|
if (date(a.created_at, "unix") < date(b.created_at, "unix")) return 1;
|
|
|
|
return 0;
|
2018-03-27 13:39:35 +11:00
|
|
|
});
|
2019-05-19 17:39:30 +10:00
|
|
|
if (type == "integrated") {
|
2018-03-27 13:39:35 +11:00
|
|
|
timeline.splice(20);
|
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
var templete = "";
|
2019-06-23 19:24:55 +10:00
|
|
|
if (localStorage.getItem("filter_" + acct_id) != "undefined") {
|
|
|
|
var mute = getFilterType(JSON.parse(localStorage.getItem("filter_" + acct_id)), "mix");
|
|
|
|
} else {
|
|
|
|
var mute = [];
|
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
Object.keys(timeline).forEach(function (key) {
|
|
|
|
var pkey = key * 1 + 1;
|
|
|
|
if (pkey < timeline.length) {
|
|
|
|
if (date(timeline[key].created_at, "unix") != date(timeline[pkey].created_at, "unix")) {
|
|
|
|
if (type == "integrated") {
|
|
|
|
templete = templete + parse([timeline[key]], '', acct_id, tlid, "", mute, "mix");
|
|
|
|
} else if (type == "plus") {
|
|
|
|
if (timeline[key].account.acct == timeline[key].account.username) {
|
|
|
|
templete = templete + parse([timeline[key]], '', acct_id, tlid, "", mute, "plus");
|
2018-03-27 13:39:35 +11:00
|
|
|
}
|
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
}
|
|
|
|
}
|
2018-01-28 23:22:43 +11:00
|
|
|
|
2019-05-19 17:39:30 +10:00
|
|
|
});
|
|
|
|
$("#landing_" + tlid).hide();
|
|
|
|
$("#timeline_" + tlid).html(templete);
|
|
|
|
mixre(acct_id, tlid, type, mute, delc, voice);
|
2018-01-28 23:22:43 +11:00
|
|
|
additional(acct_id, tlid);
|
|
|
|
jQuery("time.timeago").timeago();
|
2018-03-15 06:42:48 +11:00
|
|
|
todc();
|
2019-05-19 17:39:30 +10:00
|
|
|
});
|
|
|
|
});
|
2018-01-28 23:22:43 +11:00
|
|
|
}
|
|
|
|
|
2018-03-15 06:42:48 +11:00
|
|
|
|
2018-01-28 23:22:43 +11:00
|
|
|
//Streamingに接続
|
2019-05-19 17:39:30 +10:00
|
|
|
function mixre(acct_id, tlid, TLtype, mute, delc, voice, mode) {
|
2018-01-28 23:22:43 +11:00
|
|
|
var domain = localStorage.getItem("domain_" + acct_id);
|
2019-05-19 17:39:30 +10:00
|
|
|
var at = localStorage.getItem("acct_" + acct_id + "_at");
|
|
|
|
if (localStorage.getItem("streaming_" + acct_id)) {
|
|
|
|
var wss = localStorage.getItem("streaming_" + acct_id)
|
|
|
|
} else {
|
|
|
|
var wss = "wss://" + domain
|
2018-09-17 21:55:00 +10:00
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
var startHome = wss +
|
2018-01-28 23:22:43 +11:00
|
|
|
"/api/v1/streaming/?stream=user&access_token=" + at;
|
2019-05-19 17:39:30 +10:00
|
|
|
var startLocal = wss +
|
2018-01-28 23:22:43 +11:00
|
|
|
"/api/v1/streaming/?stream=public:local&access_token=" + at;
|
|
|
|
var wshid = websocketHome.length;
|
|
|
|
var wslid = websocketLocal.length;
|
|
|
|
websocketHome[wshid] = new WebSocket(startHome);
|
|
|
|
websocketLocal[wslid] = new WebSocket(startLocal);
|
2019-05-19 17:39:30 +10:00
|
|
|
websocketHome[wshid].onopen = function (mess) {
|
2018-08-17 03:21:40 +10:00
|
|
|
localStorage.setItem("wssH_" + tlid, wshid);
|
2019-05-19 17:39:30 +10:00
|
|
|
console.table({ "tlid": tlid, "type": "Connect Streaming API(Integrated:Home)", "domain": domain, "message": mess })
|
2018-03-11 01:22:59 +11:00
|
|
|
$("#notice_icon_" + tlid).removeClass("red-text");
|
2018-01-28 23:22:43 +11:00
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
websocketLocal[wslid].onopen = function (mess) {
|
2018-08-17 03:21:40 +10:00
|
|
|
localStorage.setItem("wssL_" + tlid, wslid);
|
2019-05-19 17:39:30 +10:00
|
|
|
console.table({ "tlid": tlid, "type": "Connect Streaming API(Integrated:Local)", "domain": domain, "message": mess })
|
2018-03-11 01:22:59 +11:00
|
|
|
$("#notice_icon_" + tlid).removeClass("red-text");
|
2018-01-28 23:22:43 +11:00
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
websocketLocal[wslid].onmessage = function (mess) {
|
|
|
|
console.log(["Receive Streaming API:(Integrated:Local)", obj]);
|
2018-01-28 23:22:43 +11:00
|
|
|
|
|
|
|
var obj = JSON.parse(JSON.parse(mess.data).payload);
|
|
|
|
var type = JSON.parse(mess.data).event;
|
|
|
|
if (type == "delete") {
|
2019-05-19 17:39:30 +10:00
|
|
|
if (delc == "true") {
|
|
|
|
$("#timeline_" + tlid + " [toot-id=" + JSON.parse(mess.data).payload + "]").addClass("emphasized");
|
|
|
|
$("#timeline_" + tlid + " [toot-id=" + JSON.parse(mess.data).payload + "]").addClass("by_delcatch");
|
|
|
|
} else {
|
2018-07-17 01:39:06 +10:00
|
|
|
$("[toot-id=" + JSON.parse(mess.data).payload + "]").hide();
|
|
|
|
$("[toot-id=" + JSON.parse(mess.data).payload + "]").remove();
|
|
|
|
}
|
|
|
|
|
2018-01-28 23:22:43 +11:00
|
|
|
} else if (type == "update") {
|
2019-05-19 17:39:30 +10:00
|
|
|
var templete = parse([obj], '', acct_id, tlid, "", mute);
|
|
|
|
if ($("#timeline_" + tlid + " [toot-id=" + obj.id + "]").length < 1) {
|
|
|
|
if (voice) {
|
2018-08-10 01:18:35 +10:00
|
|
|
say(obj.content)
|
2019-05-19 17:39:30 +10:00
|
|
|
}
|
|
|
|
var templete = parse([obj], type, acct_id, tlid, "", mute, "mix");
|
2018-01-28 23:22:43 +11:00
|
|
|
var pool = localStorage.getItem("pool_" + tlid);
|
2018-08-10 01:18:35 +10:00
|
|
|
if (pool) {
|
2018-01-28 23:22:43 +11:00
|
|
|
pool = templete + pool;
|
2018-08-10 01:18:35 +10:00
|
|
|
} else {
|
2018-01-28 23:22:43 +11:00
|
|
|
pool = templete
|
|
|
|
}
|
|
|
|
localStorage.setItem("pool_" + tlid, pool);
|
2019-05-19 17:39:30 +10:00
|
|
|
|
2018-01-28 23:22:43 +11:00
|
|
|
scrollck();
|
2019-05-19 17:39:30 +10:00
|
|
|
|
2018-01-28 23:22:43 +11:00
|
|
|
additional(acct_id, tlid);
|
|
|
|
jQuery("time.timeago").timeago();
|
2019-05-19 17:39:30 +10:00
|
|
|
} else {
|
2018-08-10 01:18:35 +10:00
|
|
|
todo("二重取得発生中");
|
|
|
|
}
|
|
|
|
|
2019-05-19 17:39:30 +10:00
|
|
|
}
|
2018-01-28 23:22:43 +11:00
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
websocketHome[wshid].onmessage = function (mess) {
|
|
|
|
console.log(["Receive Streaming API:(Integrated:Home)", obj]);
|
2018-01-28 23:22:43 +11:00
|
|
|
var obj = JSON.parse(JSON.parse(mess.data).payload);
|
|
|
|
var type = JSON.parse(mess.data).event;
|
|
|
|
if (type == "delete") {
|
2019-05-19 17:39:30 +10:00
|
|
|
if (del > 10) {
|
|
|
|
reconnector(tlid, type, acct_id, data)
|
|
|
|
} else {
|
|
|
|
localStorage.setItem("delete", del * 1 + 1)
|
2018-08-21 04:26:14 +10:00
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
if (delc == "true") {
|
2018-07-17 01:39:06 +10:00
|
|
|
$("[toot-id=" + JSON.parse(mess.data).payload + "]").addClass("emphasized");
|
|
|
|
$("[toot-id=" + JSON.parse(mess.data).payload + "]").addClass("by_delcatch");
|
2019-05-19 17:39:30 +10:00
|
|
|
} else {
|
2018-07-17 01:39:06 +10:00
|
|
|
$("[toot-id=" + JSON.parse(mess.data).payload + "]").hide();
|
|
|
|
$("[toot-id=" + JSON.parse(mess.data).payload + "]").remove();
|
|
|
|
}
|
2018-01-28 23:22:43 +11:00
|
|
|
} else if (type == "update") {
|
2018-08-21 04:26:14 +10:00
|
|
|
localStorage.removeItem("delete");
|
2019-05-19 17:39:30 +10:00
|
|
|
if (TLtype == "integrated") {
|
2018-03-27 13:39:35 +11:00
|
|
|
var templete = parse([obj], '', acct_id, tlid);
|
2019-05-19 17:39:30 +10:00
|
|
|
} else if (TLtype == "plus") {
|
|
|
|
if (obj.account.acct == obj.account.username) {
|
|
|
|
var templete = parse([obj], '', acct_id, tlid, "", mute, "mix");
|
|
|
|
} else {
|
|
|
|
var templete = "";
|
2018-03-27 13:39:35 +11:00
|
|
|
}
|
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
if ($("#timeline_" + tlid + " [toot-id=" + obj.id + "]").length < 1) {
|
|
|
|
if (voice) {
|
2018-08-10 01:18:35 +10:00
|
|
|
say(obj.content)
|
2019-05-19 17:39:30 +10:00
|
|
|
}
|
|
|
|
var templete = parse([obj], type, acct_id, tlid, "", mute, "mix");
|
2018-02-25 19:41:34 +11:00
|
|
|
var pool = localStorage.getItem("pool_" + tlid);
|
2018-08-10 01:18:35 +10:00
|
|
|
if (pool) {
|
2018-02-25 19:41:34 +11:00
|
|
|
pool = templete + pool;
|
2018-08-10 01:18:35 +10:00
|
|
|
} else {
|
2018-02-25 19:41:34 +11:00
|
|
|
pool = templete
|
2018-01-28 23:22:43 +11:00
|
|
|
}
|
2018-02-25 19:41:34 +11:00
|
|
|
localStorage.setItem("pool_" + tlid, pool);
|
2019-05-19 17:39:30 +10:00
|
|
|
|
2018-02-25 19:41:34 +11:00
|
|
|
scrollck();
|
2019-05-19 17:39:30 +10:00
|
|
|
|
2018-01-28 23:22:43 +11:00
|
|
|
additional(acct_id, tlid);
|
|
|
|
jQuery("time.timeago").timeago();
|
2019-05-19 17:39:30 +10:00
|
|
|
} else {
|
2018-08-10 01:18:35 +10:00
|
|
|
todo("二重取得発生中");
|
2018-01-28 23:22:43 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
websocketLocal[wslid].onerror = function (error) {
|
2019-04-22 04:33:56 +10:00
|
|
|
console.error('WebSocketLocal Error')
|
|
|
|
console.error(error);
|
2019-05-19 17:39:30 +10:00
|
|
|
if (mode == "error") {
|
2018-08-21 04:26:14 +10:00
|
|
|
$("#notice_icon_" + tlid).addClass("red-text");
|
|
|
|
todo('WebSocket Error ' + error);
|
2019-05-19 17:39:30 +10:00
|
|
|
} else {
|
|
|
|
var errorct = localStorage.getItem("wserror_" + tlid) * 1 + 1;
|
|
|
|
localStorage.setItem("wserror_" + tlid, errorct);
|
|
|
|
if (errorct < 3) {
|
|
|
|
reconnector(tlid, TLtype, acct_id, "", "error");
|
2019-04-22 04:30:25 +10:00
|
|
|
}
|
2018-08-21 04:26:14 +10:00
|
|
|
}
|
|
|
|
};
|
2019-05-19 17:39:30 +10:00
|
|
|
websocketLocal[wslid].onclose = function () {
|
2019-05-19 16:17:05 +10:00
|
|
|
console.warn('WebSocketLocal Closing:' + tlid);
|
2019-05-19 17:39:30 +10:00
|
|
|
if (mode == "error") {
|
2018-08-21 04:26:14 +10:00
|
|
|
$("#notice_icon_" + tlid).addClass("red-text");
|
|
|
|
todo('WebSocket Closed');
|
2019-05-19 17:39:30 +10:00
|
|
|
} else {
|
|
|
|
var errorct = localStorage.getItem("wserror_" + tlid) * 1 + 1;
|
|
|
|
localStorage.setItem("wserror_" + tlid, errorct);
|
|
|
|
if (errorct < 3) {
|
|
|
|
reconnector(tlid, TLtype, acct_id, "", "error");
|
2019-04-22 04:30:25 +10:00
|
|
|
}
|
2018-08-21 04:26:14 +10:00
|
|
|
}
|
2018-01-28 23:22:43 +11:00
|
|
|
};
|
2019-05-19 17:39:30 +10:00
|
|
|
websocketHome[wshid].onerror = function (error) {
|
|
|
|
console.error(['WebSocketHome Error', error])
|
|
|
|
if (mode == "error") {
|
2018-08-21 04:26:14 +10:00
|
|
|
$("#notice_icon_" + tlid).addClass("red-text");
|
|
|
|
todo('WebSocket Error ' + error);
|
2019-05-19 17:39:30 +10:00
|
|
|
} else {
|
|
|
|
var errorct = localStorage.getItem("wserror_" + tlid) * 1 + 1;
|
|
|
|
localStorage.setItem("wserror_" + tlid, errorct);
|
|
|
|
if (errorct < 3) {
|
|
|
|
reconnector(tlid, TLtype, acct_id, "", "error");
|
2019-04-22 04:30:25 +10:00
|
|
|
}
|
2018-08-21 04:26:14 +10:00
|
|
|
}
|
|
|
|
};
|
2019-05-19 17:39:30 +10:00
|
|
|
websocketHome[wshid].onclose = function () {
|
2019-05-19 16:17:05 +10:00
|
|
|
console.warn('WebSocketHome Closing:' + tlid);
|
2019-05-19 17:39:30 +10:00
|
|
|
if (mode == "error") {
|
2018-08-21 04:26:14 +10:00
|
|
|
$("#notice_icon_" + tlid).addClass("red-text");
|
|
|
|
todo('WebSocket Closed');
|
2019-05-19 17:39:30 +10:00
|
|
|
} else {
|
|
|
|
var errorct = localStorage.getItem("wserror_" + tlid) * 1 + 1;
|
|
|
|
localStorage.setItem("wserror_" + tlid, errorct);
|
|
|
|
if (errorct < 3) {
|
|
|
|
reconnector(tlid, TLtype, acct_id, "", "error");
|
2019-04-22 04:30:25 +10:00
|
|
|
}
|
2018-08-21 04:26:14 +10:00
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
|
2018-01-28 23:22:43 +11:00
|
|
|
};
|
2018-08-21 04:26:14 +10:00
|
|
|
|
2018-01-28 23:22:43 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
//ある程度のスクロールで発火
|
2019-05-19 17:39:30 +10:00
|
|
|
function mixmore(tlid, type) {
|
2018-01-28 23:22:43 +11:00
|
|
|
var multi = localStorage.getItem("column");
|
|
|
|
var obj = JSON.parse(multi);
|
|
|
|
var acct_id = obj[tlid].domain;
|
2019-05-19 17:39:30 +10:00
|
|
|
moreloading = true;
|
2018-01-28 23:22:43 +11:00
|
|
|
todo("Integrated TL MoreLoading...(Local)");
|
|
|
|
var domain = localStorage.getItem("domain_" + acct_id);
|
2019-05-19 17:39:30 +10:00
|
|
|
var at = localStorage.getItem("acct_" + acct_id + "_at");
|
2018-07-19 02:05:53 +10:00
|
|
|
var sid = $("#timeline_" + tlid + " .cvo").last().attr("unique-id");
|
2018-03-15 06:42:48 +11:00
|
|
|
|
|
|
|
|
2019-05-19 17:39:30 +10:00
|
|
|
var start = "https://" + domain + "/api/v1/timelines/public?local=true&max_id=" + sid;
|
2018-01-28 23:22:43 +11:00
|
|
|
fetch(start, {
|
|
|
|
method: 'GET',
|
|
|
|
headers: {
|
|
|
|
'content-type': 'application/json',
|
|
|
|
'Authorization': 'Bearer ' + at
|
|
|
|
},
|
2019-05-19 17:39:30 +10:00
|
|
|
}).then(function (response) {
|
2019-10-31 02:30:26 +11:00
|
|
|
if (!response.ok) {
|
|
|
|
response.text().then(function(text) {
|
|
|
|
setLog(response.url, response.status, text);
|
|
|
|
});
|
|
|
|
}
|
2018-01-28 23:22:43 +11:00
|
|
|
return response.json();
|
2019-05-19 17:39:30 +10:00
|
|
|
}).catch(function (error) {
|
2018-01-28 23:22:43 +11:00
|
|
|
todo(error);
|
|
|
|
console.error(error);
|
2019-05-19 17:39:30 +10:00
|
|
|
}).then(function (jsonL) {
|
|
|
|
var start = "https://" + domain + "/api/v1/timelines/home?max_id=" + sid;
|
|
|
|
fetch(start, {
|
|
|
|
method: 'GET',
|
|
|
|
headers: {
|
|
|
|
'content-type': 'application/json',
|
|
|
|
'Authorization': 'Bearer ' + at
|
|
|
|
},
|
|
|
|
}).then(function (response) {
|
2019-10-31 02:30:26 +11:00
|
|
|
if (!response.ok) {
|
|
|
|
response.text().then(function(text) {
|
|
|
|
setLog(response.url, response.status, text);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return response.json();
|
2019-05-19 17:39:30 +10:00
|
|
|
}).catch(function (error) {
|
|
|
|
todo(error);
|
|
|
|
console.error(error);
|
|
|
|
}).then(function (jsonH) {
|
|
|
|
var homearr = [];
|
|
|
|
var timeline = jsonL.concat(jsonH);
|
|
|
|
timeline.sort(function (a, b) {
|
|
|
|
if (date(a.created_at, "unix") > date(b.created_at, "unix")) return -1;
|
|
|
|
if (date(a.created_at, "unix") < date(b.created_at, "unix")) return 1;
|
|
|
|
return 0;
|
|
|
|
});
|
|
|
|
timeline.splice(20);
|
|
|
|
var templete = "";
|
|
|
|
Object.keys(timeline).forEach(function (key) {
|
|
|
|
var pkey = key * 1 + 1;
|
|
|
|
if (pkey < 20) {
|
|
|
|
if (date(timeline[key].created_at, "unix") != date(timeline[pkey].created_at, "unix")) {
|
|
|
|
if (localStorage.getItem("filter_" + acct_id) != "undefined") {
|
|
|
|
var mute = getFilterType(JSON.parse(localStorage.getItem("filter_" + acct_id)), "mix");
|
|
|
|
} else {
|
|
|
|
var mute = [];
|
2018-07-17 01:39:06 +10:00
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
if (type == "integrated") {
|
|
|
|
templete = templete + parse([timeline[key]], '', acct_id, tlid, "", mute, "mix");
|
|
|
|
} else if (type == "plus") {
|
|
|
|
if (timeline[key].account.acct == timeline[key].account.username) {
|
|
|
|
templete = templete + parse([timeline[key]], '', acct_id, tlid, "", mute, "mix");
|
2018-03-27 13:39:35 +11:00
|
|
|
}
|
|
|
|
}
|
2019-05-19 17:39:30 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
2018-01-28 23:22:43 +11:00
|
|
|
|
2019-05-19 17:39:30 +10:00
|
|
|
$("#timeline_" + tlid).append(templete);
|
2018-01-28 23:22:43 +11:00
|
|
|
additional(acct_id, tlid);
|
|
|
|
jQuery("time.timeago").timeago();
|
2019-05-19 17:39:30 +10:00
|
|
|
moreloading = false;
|
2018-01-28 23:22:43 +11:00
|
|
|
todc();
|
2019-05-19 17:39:30 +10:00
|
|
|
});
|
2018-01-28 23:22:43 +11:00
|
|
|
});
|
2019-05-19 17:39:30 +10:00
|
|
|
|
2018-01-28 23:22:43 +11:00
|
|
|
|
2018-03-15 06:42:48 +11:00
|
|
|
}
|