summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/Analyzor.java121
-rw-r--r--src/main/FarmShell.java431
-rw-r--r--timezone.txt183
3 files changed, 464 insertions, 271 deletions
diff --git a/src/main/Analyzor.java b/src/main/Analyzor.java
index 6369ece..b896f62 100644
--- a/src/main/Analyzor.java
+++ b/src/main/Analyzor.java
@@ -4,8 +4,10 @@ import analysis.BrandChecker;
import database.NamedPreparedStatement;
import database.QueryUtils;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
@@ -14,6 +16,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Map.Entry;
import java.util.Scanner;
@@ -113,33 +116,24 @@ public class Analyzor {
* @throws IOException
*/
public void sentimentAnalysis(String query) throws SQLException, IOException {
- NamedPreparedStatement tweetBrandStmt, updateRating;
+ query(query);
//read the lexicons
readLexicon();
- // if you ever need to re-apply rating, use something like:
- // UPDATE mentionsbrand SET rating = NULL WHERE ...
- if (query.isEmpty()) {
- query = "SELECT t.tweetid, t.text, b.brand FROM tweet t "
- + "JOIN mentionsbrand b USING (tweetid) "
- + "WHERE b.rating IS NULL";
+ //go to the start of te dataset
+ if (data == null) {
+ System.err.println("data is empty, try querying first");
+ return;
}
- tweetBrandStmt = new NamedPreparedStatement(connection,
- query);
- ResultSet tweetBrandResults = tweetBrandStmt.executeQuery();
-
- updateRating = new NamedPreparedStatement(connection,
- "UPDATE mentionsbrand SET rating = :rating "
- + "WHERE tweetid = :tweetid AND brand = :brand");
Double value;
String text;
//for all tuples
- while (tweetBrandResults.next()) {
+ while (data.next()) {
//get the text
- text = tweetBrandResults.getString("text");
+ text = data.getString("text");
text = splitPunctToWords(text);
// test is the tweet text you are going to analyze
String[] words = text.split("\\s+"); // text splitted into separate words
@@ -161,10 +155,12 @@ public class Analyzor {
}
}
//insert the rating into the database
- updateRating.setLong("tweetid", tweetBrandResults.getLong("tweetid"));
- updateRating.setString("brand", tweetBrandResults.getString("brand"));
- updateRating.setInt("rating", (int) (positiverate * 10));
- updateRating.executeUpdate();
+ NamedPreparedStatement m_insertRating;
+ m_insertRating = new NamedPreparedStatement(connection, QueryUtils.insertRating);
+ QueryUtils.setInsertParams(m_insertRating, data.getLong("tweetid"), data.getString("brand"), (int) (positiverate * 10));
+ m_insertRating.executeUpdate();
+ //don't print the rate
+ //System.out.println(text + ": " + (int) (positiverate * 10));
}
}
@@ -188,14 +184,14 @@ public class Analyzor {
String text;
String brand;
String[] words;
- HashMap<String, HashMap<String, Integer>> wordcloud = new HashMap<>();
+ HashMap<String,HashMap<String, Integer>> wordcloud = new HashMap<>();
while (data.next()) {
//get brand
- brand = data.getString("brand");
+ brand=data.getString("brand");
//make hashmap for each brand
- if (!wordcloud.containsKey(brand)) {
- wordcloud.put(brand, new HashMap<String, Integer>());
+ if(!wordcloud.containsKey(brand)){
+ wordcloud.put(brand, new HashMap<String,Integer>());
}
//get the text
text = data.getString("text");
@@ -206,14 +202,15 @@ public class Analyzor {
//for all words
for (String word : words) {
//if it is empty, a space or a stripe, skip it
- if (word.equals("") || word.equals(" ") || word.equals("-")) {
+ if(word.equals("") || word.equals(" ") || word.equals("-")){
continue;
}
//if the word is already in the map, increment the amount
- if (wordcloud.get(brand).containsKey(word)) {
+ if(wordcloud.get(brand).containsKey(word)){
wordcloud.get(brand).put(word, wordcloud.get(brand).get(word) + 1);
- } //if the word is not already in the map, make an entry with amount = 1
- else {
+ }
+ //if the word is not already in the map, make an entry with amount = 1
+ else{
wordcloud.get(brand).put(word, 1);
}
}
@@ -274,50 +271,60 @@ public class Analyzor {
//gets the amount of users that tweet about a brand in a timezone
//makes a csv file timezone, brand, amount
- public void timezone(String query) throws SQLException, FileNotFoundException, UnsupportedEncodingException {
+ public void timezone(String query) throws SQLException, FileNotFoundException, UnsupportedEncodingException{
query(query);
+
+ InputStream inFile = new FileInputStream("timezone.txt");
+ Scanner readFile = new Scanner(inFile);
+ HashMap<String,String> toTimezone = new HashMap<>();
+ while (readFile.hasNextLine()) {
+ String line = readFile.nextLine();
+ if(line.split(",").length>1){
+ toTimezone.put(line.split(",")[0], line.split(",")[1]);
+ }
+ }
+
+
+
//hashmap timezone, brand, amount
HashMap<String, HashMap<String, Integer>> timeMap = new HashMap<>();
String timezone;
String brand;
-
- while (data.next()) {
+
+ while(data.next()){
timezone = data.getString("timezone");
+ if (toTimezone.containsKey(timezone)){
+ timezone=toTimezone.get(timezone);
+ } else {
+ timezone="other";
+ }
brand = data.getString("brand");
//if the timezone is already in the map
- if (timeMap.containsKey(timezone)) {
+ if(timeMap.containsKey(timezone)){
//if the brand for that timezone is already in the map
- if (timeMap.get(timezone).containsKey(brand)) {
+ if(timeMap.get(timezone).containsKey(brand)){
//increment the amount
timeMap.get(timezone).put(brand, timeMap.get(timezone).get(brand) + 1);
- } //if the brand for that timezone is not yet in the map
- else {
+ }
+ //if the brand for that timezone is not yet in the map
+ else{
//make a new entry for that brand with amount = 1
timeMap.get(timezone).put(brand, 1);
}
- } //if the timezone is not yet in the map
- else {
+ }
+ //if the timezone is not yet in the map
+ else{
//make a new hashmap for this map and fill it with the brand and the amount
timeMap.put(timezone, new HashMap<String, Integer>());
timeMap.get(timezone).put(brand, 1);
}
}
- //add a legenda "timezone" that will make the legenda for the timezone map
- final int legendaSize = 6000;
-
- timeMap.put("legenda" , new HashMap<String, Integer>());
- timeMap.get("legenda").put("sony", legendaSize/6);
- timeMap.get("legenda").put("lg", legendaSize/6);
- timeMap.get("legenda").put("huawei", legendaSize/6);
- timeMap.get("legenda").put("htc", legendaSize/6);
- timeMap.get("legenda").put("samsung", legendaSize/6);
- timeMap.get("legenda").put("apple", legendaSize/6);
//make the CSV out of the map
mapToCSV(timeMap, "timezone.csv", "timezone,brand,count");
}
-
+
//replaces punctuation so it will be splitted
//also removes urls
private String splitPunctToWords(String text) {
@@ -336,25 +343,25 @@ public class Analyzor {
text = text.replaceAll("[^a-zA-Z0-9#_-]", " ");
return text;
}
-
+
//prints a hashmap into a csv for a html application
//Hashmap<key1, HashMap<key2, value>> becomes key1, key2, value
//only for String, String, Integer
- void mapToCSV(HashMap<String, HashMap<String, Integer>> map, String fileName, String firstLine)
- throws FileNotFoundException, UnsupportedEncodingException {
-
+ void mapToCSV(HashMap<String, HashMap<String, Integer>> map, String fileName, String firstLine)
+ throws FileNotFoundException, UnsupportedEncodingException{
+
PrintWriter writer = new PrintWriter(fileName, "UTF-8");
-
+
writer.println(firstLine);
-
+
//loop over brands
- for (Entry en : map.entrySet()) {
+ for(Entry en : map.entrySet()){
//loop over words
- for (Entry e : map.get(en.getKey()).entrySet()) {
+ for(Entry e : map.get(en.getKey()).entrySet()){
writer.println(en.getKey() + "," + e.getKey() + "," + e.getValue());
}
}
-
+
writer.close();
System.out.println("csv file made, please put it next to html file and run this");
}
diff --git a/src/main/FarmShell.java b/src/main/FarmShell.java
index ed1a0ff..6bf350e 100644
--- a/src/main/FarmShell.java
+++ b/src/main/FarmShell.java
@@ -1,214 +1,217 @@
-package main;
-
-import database.ConnectionBuilder;
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.NoSuchElementException;
-import java.util.Scanner;
-
-/**
- *
- * @author s123188
- */
-public class FarmShell {
-
- /**
- * A scanner for the stdin.
- */
- private final Scanner scanner = new Scanner(System.in);
-
- private Analyzor cached_analyzor;
- private final ConnectionBuilder dbConnectionBuilder;
-
- FarmShell(ConnectionBuilder dbConnectionBuilder) {
- this.dbConnectionBuilder = dbConnectionBuilder;
- }
-
- private void printPrompt() {
- System.out.print("$ ");
- }
-
- private Analyzor getAnalyzor() throws SQLException {
- if (cached_analyzor == null) {
- Connection dbCon = dbConnectionBuilder.create();
- cached_analyzor = new Analyzor(dbCon);
- }
- return cached_analyzor;
- }
-
- /**
- * Processes commands from stdin until the exit command is received or EOF.
- */
- public void process_forever() {
- System.err.println("Entering interactive shell, type 'help' for help "
- + "or 'exit' to leave. '.' repeats the previous interactive "
- + "command.");
- // print prompt for reading first command
- printPrompt();
- String lastLine = "";
- while (scanner.hasNextLine()) {
- String line = scanner.nextLine().trim();
- // repeat last command
- if (line.equals(".")) {
- line = lastLine;
- }
- if (!execute(line)) {
- // requested to terminate
- break;
- }
- if (!line.isEmpty()) {
- lastLine = line;
- }
- // print prompt for reading next line
- printPrompt();
- }
- }
-
- /**
- * Execute a single commands.
- *
- * @param cmd A single line of the command.
- * @return Whether to continue or exit the application.
- */
- public boolean execute(String cmd) {
- String[] args = cmd.trim().split("\\s+", 2);
- if (!args[0].isEmpty()) {
- // non-empty command, let's see whether it makes sense?
- return execute(args);
- }
- return true;
- }
-
- /**
- * Executes a command with optional parameters.
- *
- * @param args An array with the first argument containing the command with
- * optional parameters in following arguments.
- * @return true if more commands are allowed to be executed, false
- * otherwise.
- */
- public boolean execute(String[] args) {
- try {
- Command command = Command.fromString(args[0]);
- String[] params = Arrays.copyOfRange(args, 1, args.length);
- execute(command, params);
- } catch (IllegalArgumentException ex) {
- System.err.println(ex.getMessage());
- } catch (IOException ex) {
- System.err.println("Command " + args[0] + " failed with " + ex);
- ex.printStackTrace();
- } catch (NoSuchElementException ex) {
- if ("EXIT NOW".equals(ex.getMessage())) {
- // thrown by the "exit" command to signal exit
- return false;
- } else {
- System.err.println("ZOMG SOMETHIGN FAILED: " + ex.getMessage());
- ex.printStackTrace();
- }
- } catch (SQLException ex) {
- System.err.println("such " + ex);
- }
- // another satisfied customer, next!
- return true;
- }
-
- private void execute(Command command, String[] params) throws SQLException, IOException {
- if (params.length < command.getParamCount()) {
- throw new IllegalArgumentException("Expected "
- + command.getParamCount() + " parameters, got only "
- + params.length);
- }
- switch (command) {
- case filterbots:
- System.out.println("not yet implemented");
- break;
- case sentiment:
- // if there is no query, update all unrated items.
- if (params.length > 0) {
- getAnalyzor().sentimentAnalysis(params[0]);
- } else {
- getAnalyzor().sentimentAnalysis("");
- }
- break;
- case wordcloud:
- getAnalyzor().makeWordCloud(params[0]);
- break;
- case disco:
- getAnalyzor().disco(params[0]);
- break;
- case getBrands:
- getAnalyzor().getBrands();
- break;
- case help:
- for (String line : HELP) {
- System.out.println(line);
- }
- for (Command cmd : Command.values()) {
- System.out.printf(" %-10s", cmd.name());
- if (!cmd.getDescription().isEmpty()) {
- System.out.print(" " + cmd.getDescription());
- }
- if (cmd.getParamCount() == 1) {
- System.out.print(" (1 arg)");
- } else if (cmd.getParamCount() > 1) {
- System.out.printf(" (%d args)", cmd.getParamCount());
- }
- System.out.println();
- }
- break;
- case exit:
- throw new NoSuchElementException("EXIT NOW");
- default:
- throw new AssertionError(command.name());
- }
- }
-
- enum Command {
-
- filterbots("marks all users as bot or not", 1),
- sentiment("analyzes all tweets on brand positivity (optional arg: tweet/brand selection query)"),
- wordcloud("makes a wordcloud of the text of the tweets", 1),
- getBrands("fills the database with the brands of a tweet"),
- disco("makes a outputfile for disco", 1),
- exit("Returns to shell"),
- help("Get help");
-
- private final String description;
- private final int paramCount;
-
- Command(String description) {
- this.description = description;
- this.paramCount = 0;
- }
-
- Command(String description, int paramCount) {
- this.description = description;
- this.paramCount = paramCount;
- }
-
- public String getDescription() {
- return description;
- }
-
- public int getParamCount() {
- return paramCount;
- }
-
- public static Command fromString(String command) {
- for (Command cmd : values()) {
- if (cmd.name().equals(command)) {
- return cmd;
- }
- }
- throw new IllegalArgumentException("Unrecognized command. Hint: help");
- }
- };
-
- private final String[] HELP = new String[]{
- "Interactive TweetShell",
- "",
- "Available commands:"
- };
-}
+package main;
+
+import database.ConnectionBuilder;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.NoSuchElementException;
+import java.util.Scanner;
+
+/**
+ *
+ * @author s123188
+ */
+public class FarmShell {
+
+ /**
+ * A scanner for the stdin.
+ */
+ private final Scanner scanner = new Scanner(System.in);
+
+ private Analyzor cached_analyzor;
+ private final ConnectionBuilder dbConnectionBuilder;
+
+ FarmShell(ConnectionBuilder dbConnectionBuilder) {
+ this.dbConnectionBuilder = dbConnectionBuilder;
+ }
+
+ private void printPrompt() {
+ System.out.print("$ ");
+ }
+
+ private Analyzor getAnalyzor() throws SQLException {
+ if (cached_analyzor == null) {
+ Connection dbCon = dbConnectionBuilder.create();
+ cached_analyzor = new Analyzor(dbCon);
+ }
+ return cached_analyzor;
+ }
+
+ /**
+ * Processes commands from stdin until the exit command is received or EOF.
+ */
+ public void process_forever() {
+ System.err.println("Entering interactive shell, type 'help' for help "
+ + "or 'exit' to leave. '.' repeats the previous interactive "
+ + "command.");
+ // print prompt for reading first command
+ printPrompt();
+ String lastLine = "";
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine().trim();
+ // repeat last command
+ if (line.equals(".")) {
+ line = lastLine;
+ }
+ if (!execute(line)) {
+ // requested to terminate
+ break;
+ }
+ if (!line.isEmpty()) {
+ lastLine = line;
+ }
+ // print prompt for reading next line
+ printPrompt();
+ }
+ }
+
+ /**
+ * Execute a single commands.
+ *
+ * @param cmd A single line of the command.
+ * @return Whether to continue or exit the application.
+ */
+ public boolean execute(String cmd) {
+ String[] args = cmd.trim().split("\\s+", 2);
+ if (!args[0].isEmpty()) {
+ // non-empty command, let's see whether it makes sense?
+ return execute(args);
+ }
+ return true;
+ }
+
+ /**
+ * Executes a command with optional parameters.
+ *
+ * @param args An array with the first argument containing the command with
+ * optional parameters in following arguments.
+ * @return true if more commands are allowed to be executed, false
+ * otherwise.
+ */
+ public boolean execute(String[] args) {
+ try {
+ Command command = Command.fromString(args[0]);
+ String[] params = Arrays.copyOfRange(args, 1, args.length);
+ execute(command, params);
+ } catch (IllegalArgumentException ex) {
+ System.err.println(ex.getMessage());
+ } catch (IOException ex) {
+ System.err.println("Command " + args[0] + " failed with " + ex);
+ ex.printStackTrace();
+ } catch (NoSuchElementException ex) {
+ if ("EXIT NOW".equals(ex.getMessage())) {
+ // thrown by the "exit" command to signal exit
+ return false;
+ } else {
+ System.err.println("ZOMG SOMETHIGN FAILED: " + ex.getMessage());
+ ex.printStackTrace();
+ }
+ } catch (SQLException ex) {
+ System.err.println("such " + ex);
+ }
+ // another satisfied customer, next!
+ return true;
+ }
+
+ private void execute(Command command, String[] params) throws SQLException, IOException {
+ if (params.length < command.getParamCount()) {
+ throw new IllegalArgumentException("Expected "
+ + command.getParamCount() + " parameters, got only "
+ + params.length);
+ }
+ switch (command) {
+ case filterbots:
+ System.out.println("not yet implemented");
+ break;
+ case sentiment:
+ // if there is no query, update all unrated items.
+ if (params.length > 0) {
+ getAnalyzor().sentimentAnalysis(params[0]);
+ } else {
+ getAnalyzor().sentimentAnalysis("");
+ }
+ break;
+ case wordcloud:
+ getAnalyzor().makeWordCloud(params[0]);
+ break;
+ case timezone:
+ getAnalyzor().timezone(params[0]);
+ case disco:
+ getAnalyzor().disco(params[0]);
+ break;
+ case getBrands:
+ getAnalyzor().getBrands();
+ break;
+ case help:
+ for (String line : HELP) {
+ System.out.println(line);
+ }
+ for (Command cmd : Command.values()) {
+ System.out.printf(" %-10s", cmd.name());
+ if (!cmd.getDescription().isEmpty()) {
+ System.out.print(" " + cmd.getDescription());
+ }
+ if (cmd.getParamCount() == 1) {
+ System.out.print(" (1 arg)");
+ } else if (cmd.getParamCount() > 1) {
+ System.out.printf(" (%d args)", cmd.getParamCount());
+ }
+ System.out.println();
+ }
+ break;
+ case exit:
+ throw new NoSuchElementException("EXIT NOW");
+ default:
+ throw new AssertionError(command.name());
+ }
+ }
+
+ enum Command {
+
+ filterbots("marks all users as bot or not", 1),
+ sentiment("analyzes all tweets on brand positivity (optional arg: tweet/brand selection query)"),
+ wordcloud("makes a wordcloud of the text of the tweets", 1),
+ getBrands("fills the database with the brands of a tweet"),
+ timezone("makes a map per brand for the users", 1),
+ disco("makes a outputfile for disco", 1),
+ exit("Returns to shell"),
+ help("Get help");
+
+ private final String description;
+ private final int paramCount;
+
+ Command(String description) {
+ this.description = description;
+ this.paramCount = 0;
+ }
+
+ Command(String description, int paramCount) {
+ this.description = description;
+ this.paramCount = paramCount;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public int getParamCount() {
+ return paramCount;
+ }
+
+ public static Command fromString(String command) {
+ for (Command cmd : values()) {
+ if (cmd.name().equals(command)) {
+ return cmd;
+ }
+ }
+ throw new IllegalArgumentException("Unrecognized command. Hint: help");
+ }
+ };
+
+ private final String[] HELP = new String[]{
+ "Interactive TweetShell",
+ "",
+ "Available commands:"
+ };
+}
diff --git a/timezone.txt b/timezone.txt
new file mode 100644
index 0000000..6d06302
--- /dev/null
+++ b/timezone.txt
@@ -0,0 +1,183 @@
+Warsaw,North Europe
+Hong Kong,Hong Kong
+Stockholm,North Europe
+Canada/Pacific,Pacific Time
+Bucharest,South Europe
+Mountain Time (US & Canada),Mountain Time
+Harare,South Africa
+Dhaka,New Delhi
+Sofia,South Europe
+Melbourne,Sydney
+Buenos Aires,South South America
+Bogota,North South America
+Belgrade,South Europe
+Krasnoyarsk,Russia
+BST,West Europe
+America/New_York,
+Fiji,Sydney
+Asia/Shanghai,Hong Kong
+Dublin,West Europe
+Karachi,New Delhi
+Muscat,Abu Dhabi
+Kolkata,New Delhi
+Urumqi,Hong Kong
+Islamabad,New Delhi
+Samoa,Sydney
+Tokyo,Hong Kong
+Berlin,West Europe
+America/Phoenix,Mountain Time
+Europe/Zurich,West Europe
+Madrid,West Europe
+Kathmandu,New Delhi
+Perth,Sydney
+Eastern Time (US & Canada),Eastern Time
+Zagreb,South Europe
+Europe/Dublin,West Europe
+Taipei,Hong Kong
+Helsinki,North Europe
+Europe/Belfast,West Europe
+America/Cancun,Central America
+Bangkok,Bangkok
+Guam,Bangkok
+Wellington,Sydney
+Minsk,Russia
+Atlantic Time (Canada),Atlantic Time
+Jerusalem,Abu Dhabi
+West Central Africa,North Africa
+Irkutsk,Russia
+Asia/Calcutta,New Delhi
+Sapporo,Hong Kong
+La Paz,South South America
+Mazatlan,Central America
+Europe/Copenhagen,North Europe
+Moscow,Russia
+Kabul,Abu Dhabi
+Quito,North South America
+Kyiv,South Europe
+Yerevan,South Europe
+Darwin,Sydney
+Marshall Is.,Sydney
+Caracas,North South America
+America/Puerto_Rico,Central America
+America/Denver,Mountain Time
+Kuala Lumpur,Bangkok
+London,West Europe
+Ulaan Bataar,Russia
+Nuku'alofa,Sydney
+Newfoundland,Eastern Time
+Adelaide,Sydney
+Riga,North Europe
+Astana,Russia
+Brisbane,Sydney
+Copenhagen,North Europe
+Port Moresby,Sydney
+America/Detroit,Eastern Time
+Rome,South Europe
+Pacific Time (US & Canada),Pacific Time
+Georgetown,North South America
+America/Boise,Mountain Time
+Azores,South Europe
+Sydney,Sydney
+Osaka,Hong Kong
+Almaty,Russia
+Jakarta,Bangkok
+Midway Island,
+Casablanca,North Africa
+America/Toronto,Eastern Time
+America/Chicago,Central Time
+America/Sao_Paulo,North South America
+Arizona,Mountain Time
+JST,Hong Kong
+Alaska,Alaska
+New Delhi,New Delhi
+Auckland,Sydney
+Mid-Atlantic,Atlantic Time
+Central Time (US & Canada),Central Time
+Central America,Central America
+Seoul,Hong Kong
+Solomon Is.,Sydney
+Mumbai,New Delhi
+IST,New Delhi
+America/Mexico_City,Central America
+Kamchatka,Russia
+Vilnius,North Europe
+Amsterdam,West Europe
+Baghdad,Abu Dhabi
+Novosibirsk,Russia
+Sri Jayawardenepura,New Delhi
+Sarajevo,South Europe
+Abu Dhabi,Abu Dhabi
+Greenland,Greenland
+Brussels,West Europe
+Hobart,Sydney
+Chennai,New Delhi
+Istanbul,South Europe
+Canberra,Sydney
+Asia/Karachi,New Delhi
+America/Managua,Central America
+Tashkent,Russia
+Kuwait,Abu Dhabi
+Vienna,West Europe
+Pretoria,South Africa
+CST,Central Time
+Australia/Perth,Sydney
+Nairobi,South Africa
+Monterrey,Central America
+PST,Pacific Time
+Ekaterinburg,Russia
+America/Vancouver,Pacific Time
+Asia/Manila,Bangkok
+Asia/Bahrain,Abu Dhabi
+Asia/Jakarta,Bangkok
+America/Edmonton,Mountain Time
+Cairo,North Africa
+Monrovia,North Africa
+Bern,West Europe
+America/Los_Angeles,Pacific Time
+Tbilisi,South Europe
+Paris,West Europe
+Cape Verde Is.,North Africa
+Beijing,Hong Kong
+EST,Eastern Time
+America/Guatemala,Central America
+Bratislava,South Europe
+America/Montreal,Eastern Time
+Saskatchewan,Mountain Time
+Edinburgh,West Europe
+Brasilia,North South America
+Skopje,South Europe
+Chongqing,Hong Kong
+Ljubljana,South Europe
+Athens,South Europe
+Indiana (East),Central Time
+Guadalajara,Central America
+Tijuana,Central America
+Santiago,South South America
+Pacific/Auckland,Sydney
+America/Atikokan,Central Time
+Chihuahua,Central America
+Budapest,South Europe
+Canada/Eastern,Eastern Time
+Africa/Nairobi,South Africa
+International Date Line West,Sydney
+New Caledonia,Sydney
+Rangoon,Bangkok
+Europe/Paris,West Europe
+Hanoi,Hong Kong
+Tehran,Abu Dhabi
+Asia/Kuwait,Abu Dhabi
+Africa/Lagos,North Africa
+America/Caracas,North South America
+Mexico City,Central America
+Asia/Kuala_Lumpur,Bangkok
+Hawaii,Pacific Time
+Lima,North South America
+St. Petersburg,Russia
+Riyadh,Abu Dhabi
+Lisbon,West Europe
+Magadan,Russia
+Asia/Kolkata,New Delhi
+Singapore,Bangkok
+Tallinn,North Europe
+Prague,North Europe
+Europe/London,West Europe