Jump to content

Chat, GUID, Stats and Mapstats Logger [1.0.0.3]


ColColonCleaner

Recommended Posts

Originally Posted by ty_ger07*:

 

Not Working:

 

ClanTag coz the server don't deliver it to PRoCon thx EA/DICE!!!.

 

Isnt there a way around this? Insane limits is capable of getting the clantags!

Insane limits queries Battlelog. This plugin does not. Getting data from Battlelog is sort of a hack and originally was done without any approval. Getting data from Battlelog also had a long history originally of causing plugins to timeout or cause Procon clients to freeze up. It seems like few plugin authors are willing to put that much faith into Battlelog or invest the time into making it work for their plugin.
* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ArieK4narie*:

 

What if you do happen to have the ClanTag column in the db populated and want to use the tag in the stats, would that require a lot of changes to the plugin?

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ty_ger07*:

 

What if you do happen to have the ClanTag column in the db populated and want to use the tag in the stats, would that require a lot of changes to the plugin?

What did you do in order to make the ClanTag column populate?

 

This plugin will automatically handle the ClanTag properly if the ClanTag is not null.

Code:

if (kvp.Value.ClanTag != null)
{
   if (kvp.Value.ClanTag.Length > 0)
   {
      OdbcCom.Parameters.AddWithValue("@ClanTag", kvp.Value.ClanTag);
   }
   else
   {
      OdbcCom.Parameters.AddWithValue("@ClanTag", Convert.DBNull);
   }
}
But it will not display the ClanTag in the stats message by default. You will have to know C# and edit is plugin. There is no %clantag% replacement string. You would need to add the %clantag% replacement string to the list of replacement strings around line 3804 and also add ClanTag to the SQL query selection on lines 3740, 3751, 3763, and 3774.

 

That's for Player Stats. If you want clan tags to show up in other stats such as Top10 or that sort of thing, you need to add those replacements and SQL selections to those other functions as well.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ArieK4narie*:

 

Hi,

 

Thanks for the reply.

 

Besides Battlelog, there are several other websites where you can search Battlefield users that also return the clan tags that are connected to them.

 

First you need to run the users that you already have in the db, but since it's not nice to hammer a site with requests, i would say that a decent amount of time in between queries is needed.

 

After that you could just check when there's a new PlayerID created in the db, or maybe use a trigger on that in the db, didn't check that out yet. that would then query that new user on one of those websites and return the clan tag to be inserted in your db.

 

An example would be this: http://api.bf4stats.com/api/playerInfo_plat=pc&name=&op t=names_output=js

 

Then 'grep' the "tag": value for the ClanTag

 

I'm not familiar what their policy is on acceptable use of their website, so better figure that one out first.

 

Thanks for the directions, i guess i'll have to wait until i got some more time, since i'm not familiar with C#

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ty_ger07*:

 

Hi,

Besides Battlelog, there are several other websites where you can search Battlefield users that also return the clan tags that are connected to them.

Those other sites get their data from Battlelog or some other cache source between them and Battlelog.

 

I'm not familiar what their policy is on acceptable use of their website, so better figure that one out first.

Battlelog has a policy. I am not sure about those other sites. Originally, Battlelog did not have a policy and people abused the service without permission. Battlelog responded by throttling the service which caused some Procon plugins which used the service without permission to crash/freeze/timeout or otherwise quit functioning. So, you would definitely want to have permission to someone's service and get their permission.

 

Thanks for the directions, i guess i'll have to wait until i got some more time, since i'm not familiar with C#

I should clarify that I have not tested any of this. I am giving an educated guess.

 

A rehash of my above post with more details:

 

After you get the ClanTag column populated, my educated guess would be that you would need to modify CChatGUIDStatsLogger.inc in this way:

 

 

 

For the !stats command to show the clan tag:

 

1) Modify SQL queries on line 3883, 3894, 3906, and 3917 to include (add to the query) ClanTags.

 

An example of a modified query from line 3883:

SELECT tpd.SoldierName, SUM(tps.Score) AS Score, SUM(tps.Kills) AS Kills, SUM(tps.Deaths) AS Deaths, SUM(tps.Suicide) AS Suicide, SUM(tps.TKs) AS TKs, tpr.rankScore AS rank, (SELECT SUM(tss.CountPlayers) FROM " + this.tbl_server_stats + @" tss INNER JOIN " + this.tbl_server + @" ts ON tss.ServerID = ts.ServerID AND ServerGroup = @ServerGroup GROUP BY ts.ServerGroup ) AS allrank , SUM(tps.Playtime) AS Playtime, SUM(tps.Headshots) AS Headshots, SUM(tps.Rounds) AS Rounds, MAX(tps.Killstreak) AS Killstreak, MAX(tps.Deathstreak) AS Deathstreak, tpd.ClanTag

Do the same for the query on line 3751, 3763, and 3774.

 

2) Add the %clantag% replacement to the function by inserting it after line 3957:

 

An example of 3957 and the next line added:

result = this.ListReplace(result, "%deathstreak%", row["Deathstreak"].ToString());

result = this.ListReplace(result, "%clantag%", row["ClanTag"].ToString());

3) Add %clantag% to your server's !stats command by editing this plugin's settings.

 

This is an example of how it would be added to the default player stats output:

Serverstats for [%clantag%] %playerName%:

Score: %playerScore% %playerKills% Kills %playerHeadshots% HS %playerDeaths% Deaths K/D: %playerKDR%

Your Serverrank is: %playerRank% of %allRanks%

This is in the plugin settings in Procon.

 

 

 

Do the same thing for the Welcome stats function starting on line 3725 if you want Welcome stats to also include the clan tag. Also do the same for Top 10 stats starting on line 4006 if you want Top 10 stats to include the clan tag. ... Weapon stats starting at line 4127 ... Weapon Top 10 starting at line 4286 ... Dog Tag stats starting at line 4401 ... Player of the Day stats starting at line 4533 ... Top 10 for period stats starting at line 4701.

 

You get the idea I assume.

 

*untested*

 

 

 

There is a problem though. Back to this which starts at line 2693...

if (kvp.Value.ClanTag != null)

{

if (kvp.Value.ClanTag.Length > 0)

{

OdbcCom.Parameters.AddWithValue("@ClanTag", kvp.Value.ClanTag);

}

else

{

OdbcCom.Parameters.AddWithValue("@ClanTag", Convert.DBNull);

}

}

else

{

OdbcCom.Parameters.AddWithValue("@ClanTag", Convert.DBNull);

}

That code will cause XpKiller's plugin to reset all the player's Clan Tags back to NULL. So, even if you update their clan tags using some other source, this plugin will reset those dog tags back to NULL each time it processes a player because it will not find a valid clan tag provided to it from Procon and will reset the tags. So, you will have to defeat that part of XpKiller's plugin such as by doing this (commenting out the unwanted behavior [add double forward slashes before it] in the else statement so that it is not processed):

if (kvp.Value.ClanTag != null)

{

if (kvp.Value.ClanTag.Length > 0)

{

OdbcCom.Parameters.AddWithValue("@ClanTag", kvp.Value.ClanTag);

}

else

{

OdbcCom.Parameters.AddWithValue("@ClanTag", Convert.DBNull);

}

}

// else

// {

// OdbcCom.Parameters.AddWithValue("@ClanTag", Convert.DBNull);

// }

There is similar logic on line 2733, but you should let it insert the player's clan tag as NULL in that logic (do not modify the logic on line 2733).

The logic on line 2733 is for adding a new player who was not previously in the database. Let the plugin add the player with a NULL clan tag on line 2733. Then, you do your stuff to update player clan tags. Then, prevent this plugin from resetting clan tags to null on line 2693 such as I showed above by commenting out that behavior.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ty_ger07*:

 

Actually...

 

More about that clan tag NULL reset on line 2693:

I don't think simply commenting out the reset will work. Why? The query above it is a UPDATE query with prepared statements. Since the @ClanTag is in the prepared statement, if it is not handled one way or another, you will probably get an error that the number of arguments don't match. (It is expecting you to feed it a value but Procon doesn't give you a useful value other than NULL due to the rcon limitations) It would probably be better to remove @ClanTag completely from that UPDATE query since there is never an occasion for your use where you would want the plugin to change the data in the ClanTag column.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ArieK4narie*:

 

Yeah, i've noticed that. Commenting all of that out does help, however, on exit from the server it also gets updated it seems and changes back to NULL again. Will track that when the server is empty again so i can test.

 

When doing a !stats command, it seems that the query looks in the wrong table for some reason:

 

[statslogger]Error: GetPlayerStats: System.ArgumentException: Column 'ClanTag' does not belong to table .

at System.Data.DataRow.GetDataColumn(String columnName)

at System.Data.DataRow.get_Item(String columnName)

at PRoConEvents.CChatGUIDStatsLogger.GetPlayerStats(S tring strSpeaker, Int32 delay, String scope)

 

Although tpd.ClanTag should point to the same table as tpd.SoldierName i guess. Could it be the order in the select query where the ClanTag column comes before the SoldierName one?

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ty_ger07*:

 

When doing a !stats command, it seems that the query looks in the wrong table for some reason:

 

[statslogger]Error: GetPlayerStats: System.ArgumentException: Column 'ClanTag' does not belong to table .

at System.Data.DataRow.GetDataColumn(String columnName)

at System.Data.DataRow.get_Item(String columnName)

at PRoConEvents.CChatGUIDStatsLogger.GetPlayerStats(S tring strSpeaker, Int32 delay, String scope)

 

Although tpd.ClanTag should point to the same table as tpd.SoldierName i guess. Could it be the order in the select query where the ClanTag column comes before the SoldierName one?

It shouldn't matter which order you ask for tpd.ClanTag in the query. I don't know C#, but it seems that it may be stricter about implied statements than I am used to. I think specifying it tpd.ClanTag AS ClanTag will help.

 

Maybe this will help?

Here is line 3879 through 3958:

if (m_enRankingByScore == enumBoolYesNo.Yes)

{

if (this.m_enOverallRanking == enumBoolYesNo.Yes)

{

SQL = @"SELECT tpd.SoldierName, SUM(tps.Score) AS Score, SUM(tps.Kills) AS Kills, SUM(tps.Deaths) AS Deaths, SUM(tps.Suicide) AS Suicide, SUM(tps.TKs) AS TKs, tpr.rankScore AS rank, (SELECT SUM(tss.CountPlayers) FROM " + this.tbl_server_stats + @" tss INNER JOIN " + this.tbl_server + @" ts ON tss.ServerID = ts.ServerID AND ServerGroup = @ServerGroup GROUP BY ts.ServerGroup ) AS allrank , SUM(tps.Playtime) AS Playtime, SUM(tps.Headshots) AS Headshots,

SUM(tps.Rounds) AS Rounds, MAX(tps.Killstreak) AS Killstreak, MAX(tps.Deathstreak) AS Deathstreak, tpd.ClanTag AS ClanTag

FROM " + this.tbl_playerdata + @" tpd

INNER JOIN " + this.tbl_playerrank + @" tpr ON tpd.PlayerID = tpr.PlayerID AND tpr.ServerGroup = @ServerGroup

INNER JOIN " + this.tbl_server_player + @" tsp ON tsp.PlayerID = tpd.PlayerID

INNER JOIN " + this.tbl_playerstats + @" tps ON tsp.StatsID = tps.StatsID

WHERE tpd.SoldierName = @SoldierName

GROUP BY tpd.PlayerID";

}

else

{

SQL = @"SELECT tpd.SoldierName AS SoldierName, tps.Score AS Score, tps.Kills AS Kills, tps.Deaths AS Deaths, tps.Suicide AS Suicide, tps.TKs AS TKs, tps.rankScore AS rank, (SELECT tss.CountPlayers FROM " + this.tbl_server_stats + @" tss WHERE ServerID = @ServerID ) AS allrank ,

tps.Playtime AS Playtime, tps.Headshots AS Headshots, tps.Rounds AS Rounds, tps.Killstreak AS Killstreak, tps.Deathstreak AS Deathstreak, tpd.ClanTag AS ClanTag

FROM " + this.tbl_playerdata + @" tpd

INNER JOIN " + this.tbl_server_player + @" tsp ON tsp.PlayerID = tpd.PlayerID

INNER JOIN " + this.tbl_playerstats + @" tps ON tps.StatsID = tsp.StatsID

WHERE tsp.ServerID = @ServerID AND tpd.SoldierName = @SoldierName";

}

}

else

{

if (this.m_enOverallRanking == enumBoolYesNo.Yes)

{

SQL = @"SELECT tpd.SoldierName, SUM(tps.Score) AS Score, SUM(tps.Kills) AS Kills, SUM(tps.Deaths) AS Deaths, SUM(tps.Suicide) AS Suicide, SUM(tps.TKs) AS TKs, tpr.rankKills AS rank, (SELECT SUM(tss.CountPlayers) FROM " + this.tbl_server_stats + @" tss INNER JOIN " + this.tbl_server + @" ts ON tss.ServerID = ts.ServerID AND ServerGroup = @ServerGroup GROUP BY ts.ServerGroup ) AS allrank , SUM(tps.Playtime) AS Playtime, SUM(tps.Headshots) AS Headshots,

SUM(tps.Rounds) AS Rounds, MAX(tps.Killstreak) AS Killstreak, MAX(tps.Deathstreak) AS Deathstreak, tpd.ClanTag AS ClanTag

FROM " + this.tbl_playerdata + @" tpd

INNER JOIN " + this.tbl_playerrank + @" tpr ON tpd.PlayerID = tpr.PlayerID AND tpr.ServerGroup = @ServerGroup

INNER JOIN " + this.tbl_server_player + @" tsp ON tsp.PlayerID = tpd.PlayerID

INNER JOIN " + this.tbl_playerstats + @" tps ON tsp.StatsID = tps.StatsID

WHERE tpd.SoldierName = @SoldierName

GROUP BY tpd.PlayerID";

}

else

{

SQL = @"SELECT tpd.SoldierName AS SoldierName, tps.Score AS Score, tps.Kills AS Kills, tps.Deaths AS Deaths, tps.Suicide AS Suicide, tps.TKs AS TKs, tps.rankKills AS rank, (SELECT tss.CountPlayers FROM " + this.tbl_server_stats + @" tss WHERE ServerID = @ServerID ) AS allrank ,

tps.Playtime AS Playtime, tps.Headshots AS Headshots, tps.Rounds AS Rounds, tps.Killstreak AS Killstreak, tps.Deathstreak AS Deathstreak, tpd.ClanTag AS ClanTag

FROM " + this.tbl_playerdata + @" tpd

INNER JOIN " + this.tbl_server_player + @" tsp ON tsp.PlayerID = tpd.PlayerID

INNER JOIN " + this.tbl_playerstats + @" tps ON tps.StatsID = tsp.StatsID

WHERE tsp.ServerID = @ServerID AND tpd.SoldierName = @SoldierName";

}

}

using (MySqlCommand MyCommand = new MySqlCommand(SQL))

{

DataTable resultTable;

if (this.m_enOverallRanking == enumBoolYesNo.Yes)

{

MyCommand.Parameters.AddWithValue("@ServerGroup", this.intServerGroup);

MyCommand.Parameters.AddWithValue("@SoldierName", strSpeaker);

}

else

{

MyCommand.Parameters.AddWithValue("@ServerID", ServerID);

MyCommand.Parameters.AddWithValue("@SoldierName", strSpeaker);

}

try

{

resultTable = this.SQLquery(MyCommand);

if (resultTable.Rows != null)

{

foreach (DataRow row in resultTable.Rows)

{

result = new List(m_lstPlayerStatsMessage);

result = this.ListReplace(result, "%playerName%", row["SoldierName"].ToString());

result = this.ListReplace(result, "%playerScore%", row["Score"].ToString());

result = this.ListReplace(result, "%playerKills%", row["Kills"].ToString());

result = this.ListReplace(result, "%playerDeaths%", row["Deaths"].ToString());

result = this.ListReplace(result, "%playerSuicide%", row["Suicide"].ToString());

result = this.ListReplace(result, "%playerTKs%", row["TKs"].ToString());

result = this.ListReplace(result, "%playerRank%", row["rank"].ToString());

result = this.ListReplace(result, "%allRanks%", row["allrank"].ToString());

result = this.ListReplace(result, "%playerHeadshots%", row["Headshots"].ToString());

result = this.ListReplace(result, "%rounds%", row["Rounds"].ToString());

result = this.ListReplace(result, "%killstreak%", row["Killstreak"].ToString());

result = this.ListReplace(result, "%deathstreak%", row["Deathstreak"].ToString());

result = this.ListReplace(result, "%clantag%", row["ClanTag"].ToString());

If you want to try switching the order though and keep the tpd data with the other tpd data, feel free.

 

 

Your other question...

 

I would try:

Replace line 2674 through 2715 with:

if (this.m_ID_cache[kvp.Value.EAGuid].Id >= 1)

{

string UpdatedataSQL = @"UPDATE " + this.tbl_playerdata + @" SET SoldierName = @SoldierName, PBGUID = @PBGUID, IP_Address = @IP_Address, CountryCode = @CountryCode, GlobalRank = @GlobalRank WHERE PlayerID = @PlayerID";

using (MySqlCommand OdbcCom = new MySqlCommand(UpdatedataSQL, MySqlConn, MySqlTrans))

{

//Update

if (GlobalDebugMode.Equals("Trace"))

{

this.DebugInfo("Trace", "Update for Player " + kvp.Key);

this.DebugInfo("Trace", "SoldierName " + kvp.Key);

this.DebugInfo("Trace", "PBGUID " + kvp.Value.Guid);

this.DebugInfo("Trace", "EAGUID " + kvp.Value.EAGuid);

this.DebugInfo("Trace", "IP_Address " + kvp.Value.IP);

this.DebugInfo("Trace", "CountryCode " + kvp.Value.PlayerCountryCode);

this.DebugInfo("Trace", "GlobalRank " + kvp.Value.GlobalRank);

}

OdbcCom.Parameters.AddWithValue("@SoldierName", kvp.Key);

OdbcCom.Parameters.AddWithValue("@PBGUID", kvp.Value.Guid);

OdbcCom.Parameters.AddWithValue("@IP_Address", kvp.Value.IP);

OdbcCom.Parameters.AddWithValue("@CountryCode", kvp.Value.PlayerCountryCode);

OdbcCom.Parameters.AddWithValue("@PlayerID", this.m_ID_cache[kvp.Value.EAGuid].Id);

OdbcCom.Parameters.AddWithValue("@GlobalRank", kvp.Value.GlobalRank);

OdbcCom.ExecuteNonQuery();

}

}

(update the data but removed all references to updating the ClanTag.) Perhaps there are other parts of the code which are resetting the ClanTag which I have not found yet.
* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ty_ger07*:

 

Is it possible to add information (say or yell) at the end of the second round like this: "Teams are going to be scrambled on next round!"?

This plugin does not scramble teams.
* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ty_ger07*:

 

I know, it was an example of the text that I want to set to appear

This plugin is not designed to display random information for no particular reason. Consider a customizable plugin designed for these purposes such as Insane Limits or ProconRulz.
* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ArieK4narie*:

 

@ty_ger07

 

I've changed the suggested lines, the errors are gone and it does not change the ClanTag anymore upon exit. It also seemed that the InsertdataSQL one on line 2702 needed some adjusting for that.

 

However, i don't seem to get the Clan tags displayed yet, checked at the 'trace' level, but didn't seem to reveal anything useful

regarding that.

 

Will have to dig deeper in there.

 

ps. Did you get my private message, not sure if i sent that correctly?

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ty_ger07*:

 

Did you add %clantag% to the message string in the plugin options for the stats message? When you try !stats in the game, does it show %clantag% or what does it show in place of %clantag%?

 

Yeah, I got your PM but I do not own any game servers (haven't since BF3), so your PM unfortunately didn't mean much to me.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ArieK4narie*:

 

Ah, clear then.

 

I added the %clantag% to the several messages between lines 393-440. It's added to the SELECT queries and it has a datarow in the result table.

 

However, when i do a !stats, it still shows nothing (as in, the user only, where [Clan] User should have been), no errors though.

 

I tried it with my user and i double checked that it had the appropriate ClanTag set in the database.

 

So well, not sure where it exactly goes wrong, the query does not show up as having errors, so i assume that part is working correctly, so probably somewhere in between where the result gets returned and then loaded into the %clantag% variable.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ty_ger07*:

 

You have to add %clantag% to the stats message in the plugin settings. Adding it in the plugin source code just sets the default. Once you run the plugin on your layer just one time, it will never refer to the default again and the only way to change it is to change it in the plugin settings. Just look at this plugin's settings in procon; somewhere in there, there is a place to customize the stats message.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ArieK4narie*:

 

Ah, i never thought of that.

 

Nice it works :smile:

 

Got it running now for all commands now that display the username, so basically: stats/top10/wtop10/dogtags/potd

 

I guess the next step would be adding the Clan positions to the top10/wtop10 commands.

 

Thanks again for the help!

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ty_ger07*:

 

This is cool. It's too bad that this functionality couldn't be available by default. I am sure that XpKiller didn't want to rely on data from anywhere else other than procon for support and reliability reasons. So when I say it is too bad, I mean it is really too bad that DICE didn't include clan tags over rcon in the first place.

 

Creating your own !ClanTop10 command is doable. You would just have to mimic how the other functions are initialized and operate but substitue for a new function name, new message list, and a new query.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ArieK4narie*:

 

Exactly, it's unclear to me why they stopped with that.

 

I'll have a look at the group/Clan thingy after the weekend, i could separate it indeed, or maybe first integrate it into the existing top10 commands and have it spam both the user as well as the clan top 10's. Although that would generate too much chat spam i guess, hmz, will think about it.

 

Still need to run my mind as well on how to use the 'dogtag' data to generate the who knived who stats, but triggered in real time. I suspect that won't be possible, but a !dogtags extension to the existing command should be possible.

 

I'll keep you posted.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ty_ger07*:

 

Hi,

 

how can i make it so your demo page with more servers and the design about yours ?

 

Thank and sorry for my englisch^^

 

Greez

The stats webpage will automatically dispaly all the available servers in the database. If you made a different database for each server, you are out of luck (you should keep them all im the same database).

 

The appearance is part of a big update I have been working on but have not had a chance to finish.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by ty_ger07*:

 

Bf3-server-stats ...ALL SHI BF4...DO NOT HAVE BF3...so ....do you have bf3 sever stats web__thanks

Search the plugin enhancements forum. I think and least 3 different BF3 web stats pages were created.
* Restored post. It could be that the author is no longer active.
Link to comment
  • 2 weeks later...

Originally Posted by jeancf*:

 

Is the chatlogging archive in the database limited in time? In Plugin Setting I could not find an option to set the period for the conservation of the chats (e.g. 3days, 1 week, 1 month, ...). If it is not it would be a not feature to add and make it very useful.

 

I am sorry if I missed the answer to this question in a prior post but I could not find it.

* Restored post. It could be that the author is no longer active.
Link to comment

Originally Posted by EBassie*:

 

Is the chatlogging archive in the database limited in time? In Plugin Setting I could not find an option to set the period for the conservation of the chats (e.g. 3days, 1 week, 1 month, ...). If it is not it would be a not feature to add and make it very useful.

 

I am sorry if I missed the answer to this question in a prior post but I could not find it.

This plugin stores chats. It does not delete them

 

This is something you can do on the database side of things?

If you want to delete old chatlogs prior to a certain date.... remove them with a mysql query.

* Restored post. It could be that the author is no longer active.
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

Please review our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.