From db3edab1d973d303d0243ddc8add940d2c9ac140 Mon Sep 17 00:00:00 2001 From: Ar-Kan Date: Sat, 17 Jun 2023 14:16:24 -0300 Subject: [PATCH 1/5] Add .idea to .gitignore --- .gitignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index f6a380d..8db218f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ vendor main __debug_bin +.idea ui/build @@ -18,5 +19,5 @@ coverage.txt *.output slrp -package-lock.json -.vagrant \ No newline at end of file +package-lock.json +.vagrant From 065edf036191329e93ac8ba635b0df7bc36460d5 Mon Sep 17 00:00:00 2001 From: Ar-Kan Date: Sat, 17 Jun 2023 14:20:20 -0300 Subject: [PATCH 2/5] Setup prettier --- Makefile | 5 ++++- ui/.prettierignore | 0 ui/.prettierrc.json | 19 +++++++++++++++++++ ui/package-lock.json | 22 ++++++++++++++++++++++ ui/package.json | 4 +++- 5 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 ui/.prettierignore create mode 100644 ui/.prettierrc.json diff --git a/Makefile b/Makefile index 7938cde..ce680a3 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,9 @@ build-ui: dev-ui: npm --prefix ui start +fmt-ui: + npm --prefix ui run prettier + snapshot: build-ui goreleaser build --snapshot --rm-dist --single-target @@ -31,7 +34,7 @@ cpu-profile: block-profile: go tool pprof http://localhost:6060/debug/pprof/block -pprof: +pprof: go tool pprof -http=:8080 slrp http://127.0.0.1:6060/debug/pprof/profile race: diff --git a/ui/.prettierignore b/ui/.prettierignore new file mode 100644 index 0000000..e69de29 diff --git a/ui/.prettierrc.json b/ui/.prettierrc.json new file mode 100644 index 0000000..11409cb --- /dev/null +++ b/ui/.prettierrc.json @@ -0,0 +1,19 @@ +{ + "trailingComma": "none", + "tabWidth": 2, + "semi": true, + "singleQuote": false, + "printWidth": 300, + "arrowParens": "avoid", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "jsxSingleQuote": false, + "quoteProps": "as-needed", + "useTabs": false, + "proseWrap": "preserve", + "htmlWhitespaceSensitivity": "css", + "endOfLine": "lf", + "embeddedLanguageFormatting": "auto", + "insertPragma": false, + "requirePragma": false +} diff --git a/ui/package-lock.json b/ui/package-lock.json index 2c328d8..904b134 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -16,6 +16,7 @@ "react-router-dom": "^6.2.1" }, "devDependencies": { + "prettier": "2.8.8", "react-scripts": "^5.0.0" } }, @@ -13709,6 +13710,21 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -27241,6 +27257,12 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true + }, "pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", diff --git a/ui/package.json b/ui/package.json index f73bc00..ddea794 100644 --- a/ui/package.json +++ b/ui/package.json @@ -11,13 +11,15 @@ "react-router-dom": "^6.2.1" }, "devDependencies": { + "prettier": "2.8.8", "react-scripts": "^5.0.0" }, "scripts": { "start": "node_modules/react-scripts/bin/react-scripts.js start", "build": "node_modules/react-scripts/bin/react-scripts.js build", "test": "node_modules/react-scripts/bin/react-scripts.js test", - "eject": "node_modules/react-scripts/bin/react-scripts.js eject" + "eject": "node_modules/react-scripts/bin/react-scripts.js eject", + "prettier": "npx prettier --write ." }, "eslintConfig": { "extends": [ From c6c40aa4de90b929d91554a1bd3b269b7f906eec Mon Sep 17 00:00:00 2001 From: Ar-Kan Date: Sat, 17 Jun 2023 14:21:05 -0300 Subject: [PATCH 3/5] Prettier first execution --- ui/README.md | 2 +- ui/src/App.css | 72 +++++-- ui/src/App.js | 96 +++++---- ui/src/Blacklist.js | 103 +++++---- ui/src/History.js | 138 ++++++------ ui/src/Proxies.js | 200 ++++++++++-------- ui/src/Reverify.js | 103 +++++---- ui/src/Sources.js | 158 +++++++------- ui/src/countries.js | 500 ++++++++++++++++++++++---------------------- ui/src/index.css | 7 +- ui/src/index.js | 12 +- ui/src/util.js | 344 ++++++++++++++++-------------- 12 files changed, 944 insertions(+), 791 deletions(-) diff --git a/ui/README.md b/ui/README.md index cbeecda..83e0f09 100644 --- a/ui/README.md +++ b/ui/README.md @@ -1,3 +1,3 @@ # Developing UI -Requires `nodejs`. Starting: `make dev-ui` \ No newline at end of file +Requires `nodejs`. Starting: `make dev-ui` diff --git a/ui/src/App.css b/ui/src/App.css index accc4f4..581cfac 100644 --- a/ui/src/App.css +++ b/ui/src/App.css @@ -24,7 +24,7 @@ tr.probe-running { margin-bottom: 0; } -.table>:not(:first-child) { +.table > :not(:first-child) { border-top: none; } @@ -42,13 +42,13 @@ a { } .app-link { - color: #343a40!important; + color: #343a40 !important; text-decoration: dotted underline; transition-duration: 1s; } .app-link:hover { - color: #17a2b8!important; + color: #17a2b8 !important; } .logo img { @@ -83,44 +83,72 @@ a { } .probes .metric { - font-family: var(--bs-font-monospace)!important; + font-family: var(--bs-font-monospace) !important; } @media screen and (max-width: 1000px) { - .col-provider { display: none; } - .col-rate { display: none; } + .col-provider { + display: none; + } + .col-rate { + display: none; + } } @media screen and (max-width: 780px) { - .col-offered { display:none; } - .text-muted { display: none; } + .col-offered { + display: none; + } + .text-muted { + display: none; + } } @media screen and (max-width: 500px) { - .size { display: none;} - .proxy { display: none;} - .took { display: none; } - .col-Exclusive { display: none; } - .col-Dirty { display: none; } - .col-Contribution { display: none; } - .col-Scheduled { display: none; } - .col-Probing { display: none; } - .col-New { display: none; } - .col-Ignored { display: none; } + .size { + display: none; + } + .proxy { + display: none; + } + .took { + display: none; + } + .col-Exclusive { + display: none; + } + .col-Dirty { + display: none; + } + .col-Contribution { + display: none; + } + .col-Scheduled { + display: none; + } + .col-Probing { + display: none; + } + .col-New { + display: none; + } + .col-Ignored { + display: none; + } } .search-facet { - padding: .5em; + padding: 0.5em; } .search-facet ul { display: inline; - padding-left: .5em; + padding-left: 0.5em; } .search-facet li { display: inline; - margin-right: .5em; + margin-right: 0.5em; } small { @@ -147,4 +175,4 @@ small { top: 0.5em; color: #6c757d; padding-right: 38px; -} \ No newline at end of file +} diff --git a/ui/src/App.js b/ui/src/App.js index 9661d0c..667b5e6 100644 --- a/ui/src/App.js +++ b/ui/src/App.js @@ -1,8 +1,8 @@ import "bootstrap/dist/css/bootstrap.min.css"; import "bootstrap-icons/font/bootstrap-icons.css"; -import './App.css'; -import React from 'react'; -import {Routes, Route, NavLink, Outlet} from "react-router-dom"; +import "./App.css"; +import React from "react"; +import { Routes, Route, NavLink, Outlet } from "react-router-dom"; import { ErrorBoundary } from "./util"; import Dashboard from "./Sources"; import Proxies from "./Proxies"; @@ -11,45 +11,71 @@ import Blacklist from "./Blacklist"; import Reverify from "./Reverify"; function Header() { - return
-
-
- - slrp - -
    -
  • Overview
  • -
  • Proxies
  • -
  • History
  • -
  • Reverify
  • -
  • Blacklist
  • -
+ return ( +
+
+
+ + slrp + +
    +
  • + + Overview + +
  • +
  • + + Proxies + +
  • +
  • + + History + +
  • +
  • + + Reverify + +
  • +
  • + + Blacklist + +
  • +
+
-
-
+ + ); } function Layout() { - return
-
-
- - - -
-
+ return ( +
+
+
+ + + +
+
+ ); } function App() { - return - }> - } /> - } /> - } /> - } /> - } /> - - + return ( + + }> + } /> + } /> + } /> + } /> + } /> + + + ); } export default App; diff --git a/ui/src/Blacklist.js b/ui/src/Blacklist.js index 7b3793b..9e6e205 100644 --- a/ui/src/Blacklist.js +++ b/ui/src/Blacklist.js @@ -1,49 +1,66 @@ -import { IconHeader, LiveFilter, QueryFacets, useTitle, http } from './util' -import { Countries } from './countries'; -import { useState } from 'react'; +import { IconHeader, LiveFilter, QueryFacets, useTitle, http } from "./util"; +import { Countries } from "./countries"; +import { useState } from "react"; -function Item({Proxy, Failure, Sources, Provider, ASN, Country}) { +function Item({ Proxy, Failure, Sources, Provider, ASN, Country }) { const removeProxy = e => { - http.delete(`/blacklist/${Proxy.replace("//", '')}`) - return false - } - return - - x - - - {Proxy} {Sources.length} sources - {/* {Sources.join(', ')} */} - - {Countries[Country]?.flag} - - {Provider} - - {Failure} - + http.delete(`/blacklist/${Proxy.replace("//", "")}`); + return false; + }; + return ( + + + + x + + + + {Proxy}{" "} + + {Sources.length} sources + + {/* {Sources.join(', ')} */} + + + {Countries[Country]?.flag} + + + + {Provider} + + + {Failure} + + ); } export default function Blacklist() { - useTitle("Blacklist") + useTitle("Blacklist"); const [result, setResult] = useState(null); - return
- - {result != null &&
- - - - - - - - {result.Records.map(r => )} - -
- - - - -
-
} -
-} \ No newline at end of file + return ( +
+ + {result != null && ( +
+ + + + + + + + {result.Records.map(r => ( + + ))} + +
+ + + + +
+
+ )} +
+ ); +} diff --git a/ui/src/History.js b/ui/src/History.js index 477c09a..b85740a 100644 --- a/ui/src/History.js +++ b/ui/src/History.js @@ -1,88 +1,86 @@ -import {IconHeader, LiveFilter, QueryFacets, useTitle} from './util' -import {useState} from 'react'; -import "./History.css" +import { IconHeader, LiveFilter, QueryFacets, useTitle } from "./util"; +import { useState } from "react"; +import "./History.css"; function convertSize(bytes) { if (bytes < 1024) { - return `${bytes.toFixed()}b` + return `${bytes.toFixed()}b`; } else if (bytes < 1024 * 1024) { - return `${(bytes / 1024).toFixed()}kb` + return `${(bytes / 1024).toFixed()}kb`; } - return `${(bytes / 1024 / 1024).toFixed()}mb` + return `${(bytes / 1024 / 1024).toFixed()}mb`; } function Request(props) { - let { ID, Serial, Attempt, Ts, Method, URL, - Status, StatusCode, Proxy, Appeared, Size, - Took } = props + let { ID, Serial, Attempt, Ts, Method, URL, Status, StatusCode, Proxy, Appeared, Size, Took } = props; - let pos = URL.indexOf("/", 9) - let path = URL.substring(pos) + let pos = URL.indexOf("/", 9); + let path = URL.substring(pos); - let color = 'text-muted' + let color = "text-muted"; if (StatusCode < 300) { - color = 'text-success' + color = "text-success"; } else if (StatusCode < 500) { - color = 'text-warning' + color = "text-warning"; } // TODO: add links in backend - return - - - {new Date(Ts).toLocaleTimeString()} - - - - - {Method} - {path} - - {Serial} - - - - {StatusCode === 200 ? 200 : {StatusCode}} {Attempt} - - - - {Proxy} - {Appeared} - - - {convertSize(Size)} - - {Took}s - + return ( + + + {new Date(Ts).toLocaleTimeString()} + + + + {Method}{" "} + + {path} + + + + {Serial} + + + + + + {StatusCode === 200 ? 200 : {StatusCode}} {Attempt} + + + + {Proxy} + {" "} + {Appeared} + + {convertSize(Size)} + {Took}s + + ); } export default function History() { - useTitle("History") + useTitle("History"); const [result, setResult] = useState(null); - return
- - {result !== null &&
- - - - - - - - - - - - - - {result.Records !== null && result.Records.map(r => - )} - -
-
} -
-} \ No newline at end of file + return ( +
+ + {result !== null && ( +
+ + + + + + + + + + + + + {result.Records !== null && result.Records.map(r => )} +
+
+ )} +
+ ); +} diff --git a/ui/src/Proxies.js b/ui/src/Proxies.js index e38b3cf..bcabcd9 100644 --- a/ui/src/Proxies.js +++ b/ui/src/Proxies.js @@ -1,109 +1,131 @@ -import { LiveFilter, QueryFacets, TimeDiff, http, IconHeader, useTitle } from './util' -import { Countries } from './countries'; -import { useState } from 'react'; +import { LiveFilter, QueryFacets, TimeDiff, http, IconHeader, useTitle } from "./util"; +import { Countries } from "./countries"; +import { useState } from "react"; export default function Proxies() { - useTitle("Proxies") + useTitle("Proxies"); const [result, setResult] = useState(null); - return
- - {result !== null &&
- - - - - - - - - - - - - - - - {result.Records.map(proxy => - )} - -
ProxyOfferedSucceed -
-
} -
+ return ( +
+ + {result !== null && ( +
+ + + + + + + + + + + + + + + + {result.Records.map(proxy => ( + + ))} + +
ProxyOfferedSucceed +
+
+ )} +
+ ); } function timeTook(duration) { - let ms = duration / 1000000 + let ms = duration / 1000000; if (ms < 1000) { - return `${ms.toFixed()}ms` + return `${ms.toFixed()}ms`; } - return `${(ms/1000).toFixed(2)}s` + return `${(ms / 1000).toFixed(2)}s`; } function Entry(props) { - const proxy = props.Proxy - const {FirstSeen, LastSeen, Timeouts, Ok, ReanimateAfter, Speed, Country, Provider, ASN} = props + const proxy = props.Proxy; + const { FirstSeen, LastSeen, Timeouts, Ok, ReanimateAfter, Speed, Country, Provider, ASN } = props; const removeProxy = e => { - http.delete(`/probe/${proxy.replace("//", '')}`) - return false - } - return - - - {proxy} - - - {Countries[Country]?.flag} - - {Provider} - - {timeTook(Speed)} - - {Ok && } - {!Ok && - - } - - - - - {props.Offered} {Timeouts > 0 && - {Timeouts}} - {props.Succeed} - - x - - + http.delete(`/probe/${proxy.replace("//", "")}`); + return false; + }; + return ( + + + + {proxy} + {" "} + + + + {Countries[Country]?.flag} + + + + {Provider} + + + {timeTook(Speed)} + + {Ok && } + {!Ok && ( + + + + )} + + + + + + {props.Offered}{" "} + {Timeouts > 0 && ( + + + {Timeouts} + + )} + + + {props.Succeed} + + + + x + + + + ); } -function HourSuccessRate({HourSucceed, HourOffered}) { +function HourSuccessRate({ HourSucceed, HourOffered }) { // https://stackoverflow.com/questions/45514676/react-check-if-element-is-visible-in-dom - const rate = HourSucceed.map((s, i) => s === 0 ? 0 : 100 * s / HourOffered[i]) + const rate = HourSucceed.map((s, i) => (s === 0 ? 0 : (100 * s) / HourOffered[i])); const x = r => { - let l = r - let e = 100 - l + let l = r; + let e = 100 - l; let t = { - width: '2px', - height: '20px', - float: 'left', - border: '0', - } + width: "2px", + height: "20px", + float: "left", + border: "0" + }; if (r > 0) { - t.backgroundColor = 'green' - t.backgroundImage = `linear-gradient(0deg, #080 ${l}%, #fff ${e}%)` + t.backgroundColor = "green"; + t.backgroundImage = `linear-gradient(0deg, #080 ${l}%, #fff ${e}%)`; } - return t - } + return t; + }; // debugger - let s = {'height': '100%'} - return
- {rate.map((r, i) => -
- )} -
-} \ No newline at end of file + let s = { height: "100%" }; + return ( +
+ {rate.map((r, i) => ( +
+ ))} +
+ ); +} diff --git a/ui/src/Reverify.js b/ui/src/Reverify.js index 51654e0..b491b6d 100644 --- a/ui/src/Reverify.js +++ b/ui/src/Reverify.js @@ -1,49 +1,66 @@ -import { IconHeader, LiveFilter, QueryFacets, useTitle, http } from './util' -import { Countries } from './countries'; -import { useState } from 'react'; +import { IconHeader, LiveFilter, QueryFacets, useTitle, http } from "./util"; +import { Countries } from "./countries"; +import { useState } from "react"; -function Item({Proxy, Sources, Provider, ASN, Country, Attempt}) { +function Item({ Proxy, Sources, Provider, ASN, Country, Attempt }) { const removeProxy = e => { - http.delete(`/blacklist/${Proxy.replace("//", '')}`) - return false - } - return - - x - - - {Proxy} {Sources.length} sources - {/* {Sources.join(', ')} */} - - {Countries[Country]?.flag} - - {Provider} - - {Attempt} - + http.delete(`/blacklist/${Proxy.replace("//", "")}`); + return false; + }; + return ( + + + + x + + + + {Proxy}{" "} + + {Sources.length} sources + + {/* {Sources.join(', ')} */} + + + {Countries[Country]?.flag} + + + + {Provider} + + + {Attempt} + + ); } export default function Reverify() { - useTitle("Reverify") + useTitle("Reverify"); const [result, setResult] = useState(null); - return
- - {result != null &&
- - - - - - - - {result.Records.map(r => )} - -
- - - - -
-
} -
-} \ No newline at end of file + return ( +
+ + {result != null && ( +
+ + + + + + + + {result.Records.map(r => ( + + ))} + +
+ + + + +
+
+ )} +
+ ); +} diff --git a/ui/src/Sources.js b/ui/src/Sources.js index 289fe88..1b23611 100644 --- a/ui/src/Sources.js +++ b/ui/src/Sources.js @@ -1,24 +1,22 @@ -import { Card, IconHeader, TimeDiff, useInterval, useTitle, http } from './util' -import { useState } from 'react'; +import { Card, IconHeader, TimeDiff, useInterval, useTitle, http } from "./util"; +import { useState } from "react"; -const overall = ['Exclusive', 'Dirty', 'Contribution'] -const pipeline = ['Scheduled', 'New', 'Probing'] -const stats = ['Found', 'Timeouts', 'Blacklisted', 'Ignored'] +const overall = ["Exclusive", "Dirty", "Contribution"]; +const pipeline = ["Scheduled", "New", "Probing"]; +const stats = ["Found", "Timeouts", "Blacklisted", "Ignored"]; function successRate(v) { - if (v['Found'] === 0) { - return 0 + if (v["Found"] === 0) { + return 0; } - return 100 * v['Found'] / stats.reduce((x,col) => x + v[col], 0) + return (100 * v["Found"]) / stats.reduce((x, col) => x + v[col], 0); } function SourceOverview({ sources }) { - var summary = {'_': 1} - const cols = pipeline.concat(stats) - cols.forEach(col => summary[col] = 0) - sources.forEach(probe => - cols.forEach(col => - summary[col] += probe[col])) + var summary = { _: 1 }; + const cols = pipeline.concat(stats); + cols.forEach(col => (summary[col] = 0)); + sources.forEach(probe => cols.forEach(col => (summary[col] += probe[col]))); return (
@@ -39,9 +37,9 @@ function SourceOverview({ sources }) { - {sources.map(probe => + {sources.map(probe => ( - )} + ))} @@ -56,86 +54,104 @@ function SourceOverview({ sources }) { function Cols(props) { return [ - overall.map(col => - ), - pipeline.map(col => - ), - , - stats.map(col => - ) - ] + overall.map(col => ( + + )), + pipeline.map(col => ( + + )), + , + stats.map(col => ( + + )) + ]; } function tinyNum(n) { if (!n) { - return 0 + return 0; } if (n < 1000) { - return n + return n; } else if (n < 1000000) { - return (n/1000).toFixed()+'k' + return (n / 1000).toFixed() + "k"; } - return (n/1000000).toFixed(1)+'m' + return (n / 1000000).toFixed(1) + "m"; } function Probe(props) { - let {Name, State, Progress, Failure, EstFinish, NextRefresh, UrlPrefix, Homepage} = props - let style = {} - let rowClass = "" - let running = State === "running" + let { Name, State, Progress, Failure, EstFinish, NextRefresh, UrlPrefix, Homepage } = props; + let style = {}; + let rowClass = ""; + let running = State === "running"; if (running && Progress > 1) { - rowClass = "probe-running" - const lg = `linear-gradient(90deg, #080 ${Progress}%, #fff 0%)` - style.backgroundImage = lg + rowClass = "probe-running"; + const lg = `linear-gradient(90deg, #080 ${Progress}%, #fff 0%)`; + style.backgroundImage = lg; } - let refresh = running - ? - : + let refresh = running ? : ; let icons = { - 'running': , - 'failed': , - 'idle': , - } - return - - - + running: , + failed: , + idle: + }; + return ( + + + + + ); } export default function Dashboard() { - useTitle("Overview") + useTitle("Overview"); const [dashboard, setDashboard] = useState(null); const [delay, setDelay] = useState(1000); useInterval(() => { - http.get('/dashboard') + http + .get("/dashboard") .then(response => setDashboard(response.data)) .catch(err => { if (err.isAxiosError) { - console.error(err.response.data) + console.error(err.response.data); } - setDelay(null) - }) - }, delay) + setDelay(null); + }); + }, delay); if (dashboard == null) { - return
-
- Loading... + return ( +
+
+ Loading... +
-
+ ); } - return
-
- {dashboard.Cards.map(card => - )} + return ( +
+
+ {dashboard.Cards.map(card => ( + + ))} +
+
- -
-} \ No newline at end of file + ); +} diff --git a/ui/src/countries.js b/ui/src/countries.js index 4834253..f7b9a60 100644 --- a/ui/src/countries.js +++ b/ui/src/countries.js @@ -1,252 +1,252 @@ // generated automatically from https://apps.timwhitlock.info/emoji/tables/iso3166 export const Countries = { - "AD": {flag: "๐Ÿ‡ฆ๐Ÿ‡ฉ", name: "Andorra"}, - "AE": {flag: "๐Ÿ‡ฆ๐Ÿ‡ช", name: "United Arab Emirates"}, - "AF": {flag: "๐Ÿ‡ฆ๐Ÿ‡ซ", name: "Afghanistan"}, - "AG": {flag: "๐Ÿ‡ฆ๐Ÿ‡ฌ", name: "Antigua and Barbuda"}, - "AI": {flag: "๐Ÿ‡ฆ๐Ÿ‡ฎ", name: "Anguilla"}, - "AL": {flag: "๐Ÿ‡ฆ๐Ÿ‡ฑ", name: "Albania"}, - "AM": {flag: "๐Ÿ‡ฆ๐Ÿ‡ฒ", name: "Armenia"}, - "AO": {flag: "๐Ÿ‡ฆ๐Ÿ‡ด", name: "Angola"}, - "AQ": {flag: "๐Ÿ‡ฆ๐Ÿ‡ถ", name: "Antarctica"}, - "AR": {flag: "๐Ÿ‡ฆ๐Ÿ‡ท", name: "Argentina"}, - "AS": {flag: "๐Ÿ‡ฆ๐Ÿ‡ธ", name: "American Samoa"}, - "AT": {flag: "๐Ÿ‡ฆ๐Ÿ‡น", name: "Austria"}, - "AU": {flag: "๐Ÿ‡ฆ๐Ÿ‡บ", name: "Australia"}, - "AW": {flag: "๐Ÿ‡ฆ๐Ÿ‡ผ", name: "Aruba"}, - "AX": {flag: "๐Ÿ‡ฆ๐Ÿ‡ฝ", name: "ร…land Islands"}, - "AZ": {flag: "๐Ÿ‡ฆ๐Ÿ‡ฟ", name: "Azerbaijan"}, - "BA": {flag: "๐Ÿ‡ง๐Ÿ‡ฆ", name: "Bosnia and Herzegovina"}, - "BB": {flag: "๐Ÿ‡ง๐Ÿ‡ง", name: "Barbados"}, - "BD": {flag: "๐Ÿ‡ง๐Ÿ‡ฉ", name: "Bangladesh"}, - "BE": {flag: "๐Ÿ‡ง๐Ÿ‡ช", name: "Belgium"}, - "BF": {flag: "๐Ÿ‡ง๐Ÿ‡ซ", name: "Burkina Faso"}, - "BG": {flag: "๐Ÿ‡ง๐Ÿ‡ฌ", name: "Bulgaria"}, - "BH": {flag: "๐Ÿ‡ง๐Ÿ‡ญ", name: "Bahrain"}, - "BI": {flag: "๐Ÿ‡ง๐Ÿ‡ฎ", name: "Burundi"}, - "BJ": {flag: "๐Ÿ‡ง๐Ÿ‡ฏ", name: "Benin"}, - "BL": {flag: "๐Ÿ‡ง๐Ÿ‡ฑ", name: "Saint Barthรฉlemy"}, - "BM": {flag: "๐Ÿ‡ง๐Ÿ‡ฒ", name: "Bermuda"}, - "BN": {flag: "๐Ÿ‡ง๐Ÿ‡ณ", name: "Brunei Darussalam"}, - "BO": {flag: "๐Ÿ‡ง๐Ÿ‡ด", name: "Bolivia"}, - "BQ": {flag: "๐Ÿ‡ง๐Ÿ‡ถ", name: "Bonaire, Sint Eustatius and Saba"}, - "BR": {flag: "๐Ÿ‡ง๐Ÿ‡ท", name: "Brazil"}, - "BS": {flag: "๐Ÿ‡ง๐Ÿ‡ธ", name: "Bahamas"}, - "BT": {flag: "๐Ÿ‡ง๐Ÿ‡น", name: "Bhutan"}, - "BV": {flag: "๐Ÿ‡ง๐Ÿ‡ป", name: "Bouvet Island"}, - "BW": {flag: "๐Ÿ‡ง๐Ÿ‡ผ", name: "Botswana"}, - "BY": {flag: "๐Ÿ‡ง๐Ÿ‡พ", name: "Belarus"}, - "BZ": {flag: "๐Ÿ‡ง๐Ÿ‡ฟ", name: "Belize"}, - "CA": {flag: "๐Ÿ‡จ๐Ÿ‡ฆ", name: "Canada"}, - "CC": {flag: "๐Ÿ‡จ๐Ÿ‡จ", name: "Cocos (Keeling) Islands"}, - "CD": {flag: "๐Ÿ‡จ๐Ÿ‡ฉ", name: "Congo"}, - "CF": {flag: "๐Ÿ‡จ๐Ÿ‡ซ", name: "Central African Republic"}, - "CG": {flag: "๐Ÿ‡จ๐Ÿ‡ฌ", name: "Congo"}, - "CH": {flag: "๐Ÿ‡จ๐Ÿ‡ญ", name: "Switzerland"}, - "CI": {flag: "๐Ÿ‡จ๐Ÿ‡ฎ", name: "Cรดte D'Ivoire"}, - "CK": {flag: "๐Ÿ‡จ๐Ÿ‡ฐ", name: "Cook Islands"}, - "CL": {flag: "๐Ÿ‡จ๐Ÿ‡ฑ", name: "Chile"}, - "CM": {flag: "๐Ÿ‡จ๐Ÿ‡ฒ", name: "Cameroon"}, - "CN": {flag: "๐Ÿ‡จ๐Ÿ‡ณ", name: "China"}, - "CO": {flag: "๐Ÿ‡จ๐Ÿ‡ด", name: "Colombia"}, - "CR": {flag: "๐Ÿ‡จ๐Ÿ‡ท", name: "Costa Rica"}, - "CU": {flag: "๐Ÿ‡จ๐Ÿ‡บ", name: "Cuba"}, - "CV": {flag: "๐Ÿ‡จ๐Ÿ‡ป", name: "Cape Verde"}, - "CW": {flag: "๐Ÿ‡จ๐Ÿ‡ผ", name: "Curaรงao"}, - "CX": {flag: "๐Ÿ‡จ๐Ÿ‡ฝ", name: "Christmas Island"}, - "CY": {flag: "๐Ÿ‡จ๐Ÿ‡พ", name: "Cyprus"}, - "CZ": {flag: "๐Ÿ‡จ๐Ÿ‡ฟ", name: "Czech Republic"}, - "DE": {flag: "๐Ÿ‡ฉ๐Ÿ‡ช", name: "Germany"}, - "DJ": {flag: "๐Ÿ‡ฉ๐Ÿ‡ฏ", name: "Djibouti"}, - "DK": {flag: "๐Ÿ‡ฉ๐Ÿ‡ฐ", name: "Denmark"}, - "DM": {flag: "๐Ÿ‡ฉ๐Ÿ‡ฒ", name: "Dominica"}, - "DO": {flag: "๐Ÿ‡ฉ๐Ÿ‡ด", name: "Dominican Republic"}, - "DZ": {flag: "๐Ÿ‡ฉ๐Ÿ‡ฟ", name: "Algeria"}, - "EC": {flag: "๐Ÿ‡ช๐Ÿ‡จ", name: "Ecuador"}, - "EE": {flag: "๐Ÿ‡ช๐Ÿ‡ช", name: "Estonia"}, - "EG": {flag: "๐Ÿ‡ช๐Ÿ‡ฌ", name: "Egypt"}, - "EH": {flag: "๐Ÿ‡ช๐Ÿ‡ญ", name: "Western Sahara"}, - "ER": {flag: "๐Ÿ‡ช๐Ÿ‡ท", name: "Eritrea"}, - "ES": {flag: "๐Ÿ‡ช๐Ÿ‡ธ", name: "Spain"}, - "ET": {flag: "๐Ÿ‡ช๐Ÿ‡น", name: "Ethiopia"}, - "FI": {flag: "๐Ÿ‡ซ๐Ÿ‡ฎ", name: "Finland"}, - "FJ": {flag: "๐Ÿ‡ซ๐Ÿ‡ฏ", name: "Fiji"}, - "FK": {flag: "๐Ÿ‡ซ๐Ÿ‡ฐ", name: "Falkland Islands (Malvinas)"}, - "FM": {flag: "๐Ÿ‡ซ๐Ÿ‡ฒ", name: "Micronesia"}, - "FO": {flag: "๐Ÿ‡ซ๐Ÿ‡ด", name: "Faroe Islands"}, - "FR": {flag: "๐Ÿ‡ซ๐Ÿ‡ท", name: "France"}, - "GA": {flag: "๐Ÿ‡ฌ๐Ÿ‡ฆ", name: "Gabon"}, - "GB": {flag: "๐Ÿ‡ฌ๐Ÿ‡ง", name: "United Kingdom"}, - "GD": {flag: "๐Ÿ‡ฌ๐Ÿ‡ฉ", name: "Grenada"}, - "GE": {flag: "๐Ÿ‡ฌ๐Ÿ‡ช", name: "Georgia"}, - "GF": {flag: "๐Ÿ‡ฌ๐Ÿ‡ซ", name: "French Guiana"}, - "GG": {flag: "๐Ÿ‡ฌ๐Ÿ‡ฌ", name: "Guernsey"}, - "GH": {flag: "๐Ÿ‡ฌ๐Ÿ‡ญ", name: "Ghana"}, - "GI": {flag: "๐Ÿ‡ฌ๐Ÿ‡ฎ", name: "Gibraltar"}, - "GL": {flag: "๐Ÿ‡ฌ๐Ÿ‡ฑ", name: "Greenland"}, - "GM": {flag: "๐Ÿ‡ฌ๐Ÿ‡ฒ", name: "Gambia"}, - "GN": {flag: "๐Ÿ‡ฌ๐Ÿ‡ณ", name: "Guinea"}, - "GP": {flag: "๐Ÿ‡ฌ๐Ÿ‡ต", name: "Guadeloupe"}, - "GQ": {flag: "๐Ÿ‡ฌ๐Ÿ‡ถ", name: "Equatorial Guinea"}, - "GR": {flag: "๐Ÿ‡ฌ๐Ÿ‡ท", name: "Greece"}, - "GS": {flag: "๐Ÿ‡ฌ๐Ÿ‡ธ", name: "South Georgia"}, - "GT": {flag: "๐Ÿ‡ฌ๐Ÿ‡น", name: "Guatemala"}, - "GU": {flag: "๐Ÿ‡ฌ๐Ÿ‡บ", name: "Guam"}, - "GW": {flag: "๐Ÿ‡ฌ๐Ÿ‡ผ", name: "Guinea-Bissau"}, - "GY": {flag: "๐Ÿ‡ฌ๐Ÿ‡พ", name: "Guyana"}, - "HK": {flag: "๐Ÿ‡ญ๐Ÿ‡ฐ", name: "Hong Kong"}, - "HM": {flag: "๐Ÿ‡ญ๐Ÿ‡ฒ", name: "Heard Island and Mcdonald Islands"}, - "HN": {flag: "๐Ÿ‡ญ๐Ÿ‡ณ", name: "Honduras"}, - "HR": {flag: "๐Ÿ‡ญ๐Ÿ‡ท", name: "Croatia"}, - "HT": {flag: "๐Ÿ‡ญ๐Ÿ‡น", name: "Haiti"}, - "HU": {flag: "๐Ÿ‡ญ๐Ÿ‡บ", name: "Hungary"}, - "ID": {flag: "๐Ÿ‡ฎ๐Ÿ‡ฉ", name: "Indonesia"}, - "IE": {flag: "๐Ÿ‡ฎ๐Ÿ‡ช", name: "Ireland"}, - "IL": {flag: "๐Ÿ‡ฎ๐Ÿ‡ฑ", name: "Israel"}, - "IM": {flag: "๐Ÿ‡ฎ๐Ÿ‡ฒ", name: "Isle of Man"}, - "IN": {flag: "๐Ÿ‡ฎ๐Ÿ‡ณ", name: "India"}, - "IO": {flag: "๐Ÿ‡ฎ๐Ÿ‡ด", name: "British Indian Ocean Territory"}, - "IQ": {flag: "๐Ÿ‡ฎ๐Ÿ‡ถ", name: "Iraq"}, - "IR": {flag: "๐Ÿ‡ฎ๐Ÿ‡ท", name: "Iran"}, - "IS": {flag: "๐Ÿ‡ฎ๐Ÿ‡ธ", name: "Iceland"}, - "IT": {flag: "๐Ÿ‡ฎ๐Ÿ‡น", name: "Italy"}, - "JE": {flag: "๐Ÿ‡ฏ๐Ÿ‡ช", name: "Jersey"}, - "JM": {flag: "๐Ÿ‡ฏ๐Ÿ‡ฒ", name: "Jamaica"}, - "JO": {flag: "๐Ÿ‡ฏ๐Ÿ‡ด", name: "Jordan"}, - "JP": {flag: "๐Ÿ‡ฏ๐Ÿ‡ต", name: "Japan"}, - "KE": {flag: "๐Ÿ‡ฐ๐Ÿ‡ช", name: "Kenya"}, - "KG": {flag: "๐Ÿ‡ฐ๐Ÿ‡ฌ", name: "Kyrgyzstan"}, - "KH": {flag: "๐Ÿ‡ฐ๐Ÿ‡ญ", name: "Cambodia"}, - "KI": {flag: "๐Ÿ‡ฐ๐Ÿ‡ฎ", name: "Kiribati"}, - "KM": {flag: "๐Ÿ‡ฐ๐Ÿ‡ฒ", name: "Comoros"}, - "KN": {flag: "๐Ÿ‡ฐ๐Ÿ‡ณ", name: "Saint Kitts and Nevis"}, - "KP": {flag: "๐Ÿ‡ฐ๐Ÿ‡ต", name: "North Korea"}, - "KR": {flag: "๐Ÿ‡ฐ๐Ÿ‡ท", name: "South Korea"}, - "KW": {flag: "๐Ÿ‡ฐ๐Ÿ‡ผ", name: "Kuwait"}, - "KY": {flag: "๐Ÿ‡ฐ๐Ÿ‡พ", name: "Cayman Islands"}, - "KZ": {flag: "๐Ÿ‡ฐ๐Ÿ‡ฟ", name: "Kazakhstan"}, - "LA": {flag: "๐Ÿ‡ฑ๐Ÿ‡ฆ", name: "Lao People's Democratic Republic"}, - "LB": {flag: "๐Ÿ‡ฑ๐Ÿ‡ง", name: "Lebanon"}, - "LC": {flag: "๐Ÿ‡ฑ๐Ÿ‡จ", name: "Saint Lucia"}, - "LI": {flag: "๐Ÿ‡ฑ๐Ÿ‡ฎ", name: "Liechtenstein"}, - "LK": {flag: "๐Ÿ‡ฑ๐Ÿ‡ฐ", name: "Sri Lanka"}, - "LR": {flag: "๐Ÿ‡ฑ๐Ÿ‡ท", name: "Liberia"}, - "LS": {flag: "๐Ÿ‡ฑ๐Ÿ‡ธ", name: "Lesotho"}, - "LT": {flag: "๐Ÿ‡ฑ๐Ÿ‡น", name: "Lithuania"}, - "LU": {flag: "๐Ÿ‡ฑ๐Ÿ‡บ", name: "Luxembourg"}, - "LV": {flag: "๐Ÿ‡ฑ๐Ÿ‡ป", name: "Latvia"}, - "LY": {flag: "๐Ÿ‡ฑ๐Ÿ‡พ", name: "Libya"}, - "MA": {flag: "๐Ÿ‡ฒ๐Ÿ‡ฆ", name: "Morocco"}, - "MC": {flag: "๐Ÿ‡ฒ๐Ÿ‡จ", name: "Monaco"}, - "MD": {flag: "๐Ÿ‡ฒ๐Ÿ‡ฉ", name: "Moldova"}, - "ME": {flag: "๐Ÿ‡ฒ๐Ÿ‡ช", name: "Montenegro"}, - "MF": {flag: "๐Ÿ‡ฒ๐Ÿ‡ซ", name: "Saint Martin (French Part)"}, - "MG": {flag: "๐Ÿ‡ฒ๐Ÿ‡ฌ", name: "Madagascar"}, - "MH": {flag: "๐Ÿ‡ฒ๐Ÿ‡ญ", name: "Marshall Islands"}, - "MK": {flag: "๐Ÿ‡ฒ๐Ÿ‡ฐ", name: "Macedonia"}, - "ML": {flag: "๐Ÿ‡ฒ๐Ÿ‡ฑ", name: "Mali"}, - "MM": {flag: "๐Ÿ‡ฒ๐Ÿ‡ฒ", name: "Myanmar"}, - "MN": {flag: "๐Ÿ‡ฒ๐Ÿ‡ณ", name: "Mongolia"}, - "MO": {flag: "๐Ÿ‡ฒ๐Ÿ‡ด", name: "Macao"}, - "MP": {flag: "๐Ÿ‡ฒ๐Ÿ‡ต", name: "Northern Mariana Islands"}, - "MQ": {flag: "๐Ÿ‡ฒ๐Ÿ‡ถ", name: "Martinique"}, - "MR": {flag: "๐Ÿ‡ฒ๐Ÿ‡ท", name: "Mauritania"}, - "MS": {flag: "๐Ÿ‡ฒ๐Ÿ‡ธ", name: "Montserrat"}, - "MT": {flag: "๐Ÿ‡ฒ๐Ÿ‡น", name: "Malta"}, - "MU": {flag: "๐Ÿ‡ฒ๐Ÿ‡บ", name: "Mauritius"}, - "MV": {flag: "๐Ÿ‡ฒ๐Ÿ‡ป", name: "Maldives"}, - "MW": {flag: "๐Ÿ‡ฒ๐Ÿ‡ผ", name: "Malawi"}, - "MX": {flag: "๐Ÿ‡ฒ๐Ÿ‡ฝ", name: "Mexico"}, - "MY": {flag: "๐Ÿ‡ฒ๐Ÿ‡พ", name: "Malaysia"}, - "MZ": {flag: "๐Ÿ‡ฒ๐Ÿ‡ฟ", name: "Mozambique"}, - "NA": {flag: "๐Ÿ‡ณ๐Ÿ‡ฆ", name: "Namibia"}, - "NC": {flag: "๐Ÿ‡ณ๐Ÿ‡จ", name: "New Caledonia"}, - "NE": {flag: "๐Ÿ‡ณ๐Ÿ‡ช", name: "Niger"}, - "NF": {flag: "๐Ÿ‡ณ๐Ÿ‡ซ", name: "Norfolk Island"}, - "NG": {flag: "๐Ÿ‡ณ๐Ÿ‡ฌ", name: "Nigeria"}, - "NI": {flag: "๐Ÿ‡ณ๐Ÿ‡ฎ", name: "Nicaragua"}, - "NL": {flag: "๐Ÿ‡ณ๐Ÿ‡ฑ", name: "Netherlands"}, - "NO": {flag: "๐Ÿ‡ณ๐Ÿ‡ด", name: "Norway"}, - "NP": {flag: "๐Ÿ‡ณ๐Ÿ‡ต", name: "Nepal"}, - "NR": {flag: "๐Ÿ‡ณ๐Ÿ‡ท", name: "Nauru"}, - "NU": {flag: "๐Ÿ‡ณ๐Ÿ‡บ", name: "Niue"}, - "NZ": {flag: "๐Ÿ‡ณ๐Ÿ‡ฟ", name: "New Zealand"}, - "OM": {flag: "๐Ÿ‡ด๐Ÿ‡ฒ", name: "Oman"}, - "PA": {flag: "๐Ÿ‡ต๐Ÿ‡ฆ", name: "Panama"}, - "PE": {flag: "๐Ÿ‡ต๐Ÿ‡ช", name: "Peru"}, - "PF": {flag: "๐Ÿ‡ต๐Ÿ‡ซ", name: "French Polynesia"}, - "PG": {flag: "๐Ÿ‡ต๐Ÿ‡ฌ", name: "Papua New Guinea"}, - "PH": {flag: "๐Ÿ‡ต๐Ÿ‡ญ", name: "Philippines"}, - "PK": {flag: "๐Ÿ‡ต๐Ÿ‡ฐ", name: "Pakistan"}, - "PL": {flag: "๐Ÿ‡ต๐Ÿ‡ฑ", name: "Poland"}, - "PM": {flag: "๐Ÿ‡ต๐Ÿ‡ฒ", name: "Saint Pierre and Miquelon"}, - "PN": {flag: "๐Ÿ‡ต๐Ÿ‡ณ", name: "Pitcairn"}, - "PR": {flag: "๐Ÿ‡ต๐Ÿ‡ท", name: "Puerto Rico"}, - "PS": {flag: "๐Ÿ‡ต๐Ÿ‡ธ", name: "Palestinian Territory"}, - "PT": {flag: "๐Ÿ‡ต๐Ÿ‡น", name: "Portugal"}, - "PW": {flag: "๐Ÿ‡ต๐Ÿ‡ผ", name: "Palau"}, - "PY": {flag: "๐Ÿ‡ต๐Ÿ‡พ", name: "Paraguay"}, - "QA": {flag: "๐Ÿ‡ถ๐Ÿ‡ฆ", name: "Qatar"}, - "RE": {flag: "๐Ÿ‡ท๐Ÿ‡ช", name: "Rรฉunion"}, - "RO": {flag: "๐Ÿ‡ท๐Ÿ‡ด", name: "Romania"}, - "RS": {flag: "๐Ÿ‡ท๐Ÿ‡ธ", name: "Serbia"}, - "RU": {flag: "๐Ÿ‡ท๐Ÿ‡บ", name: "Russia"}, - "RW": {flag: "๐Ÿ‡ท๐Ÿ‡ผ", name: "Rwanda"}, - "SA": {flag: "๐Ÿ‡ธ๐Ÿ‡ฆ", name: "Saudi Arabia"}, - "SB": {flag: "๐Ÿ‡ธ๐Ÿ‡ง", name: "Solomon Islands"}, - "SC": {flag: "๐Ÿ‡ธ๐Ÿ‡จ", name: "Seychelles"}, - "SD": {flag: "๐Ÿ‡ธ๐Ÿ‡ฉ", name: "Sudan"}, - "SE": {flag: "๐Ÿ‡ธ๐Ÿ‡ช", name: "Sweden"}, - "SG": {flag: "๐Ÿ‡ธ๐Ÿ‡ฌ", name: "Singapore"}, - "SH": {flag: "๐Ÿ‡ธ๐Ÿ‡ญ", name: "Saint Helena, Ascension and Tristan Da Cunha"}, - "SI": {flag: "๐Ÿ‡ธ๐Ÿ‡ฎ", name: "Slovenia"}, - "SJ": {flag: "๐Ÿ‡ธ๐Ÿ‡ฏ", name: "Svalbard and Jan Mayen"}, - "SK": {flag: "๐Ÿ‡ธ๐Ÿ‡ฐ", name: "Slovakia"}, - "SL": {flag: "๐Ÿ‡ธ๐Ÿ‡ฑ", name: "Sierra Leone"}, - "SM": {flag: "๐Ÿ‡ธ๐Ÿ‡ฒ", name: "San Marino"}, - "SN": {flag: "๐Ÿ‡ธ๐Ÿ‡ณ", name: "Senegal"}, - "SO": {flag: "๐Ÿ‡ธ๐Ÿ‡ด", name: "Somalia"}, - "SR": {flag: "๐Ÿ‡ธ๐Ÿ‡ท", name: "Suriname"}, - "SS": {flag: "๐Ÿ‡ธ๐Ÿ‡ธ", name: "South Sudan"}, - "ST": {flag: "๐Ÿ‡ธ๐Ÿ‡น", name: "Sao Tome and Principe"}, - "SV": {flag: "๐Ÿ‡ธ๐Ÿ‡ป", name: "El Salvador"}, - "SX": {flag: "๐Ÿ‡ธ๐Ÿ‡ฝ", name: "Sint Maarten (Dutch Part)"}, - "SY": {flag: "๐Ÿ‡ธ๐Ÿ‡พ", name: "Syrian Arab Republic"}, - "SZ": {flag: "๐Ÿ‡ธ๐Ÿ‡ฟ", name: "Swaziland"}, - "TC": {flag: "๐Ÿ‡น๐Ÿ‡จ", name: "Turks and Caicos Islands"}, - "TD": {flag: "๐Ÿ‡น๐Ÿ‡ฉ", name: "Chad"}, - "TF": {flag: "๐Ÿ‡น๐Ÿ‡ซ", name: "French Southern Territories"}, - "TG": {flag: "๐Ÿ‡น๐Ÿ‡ฌ", name: "Togo"}, - "TH": {flag: "๐Ÿ‡น๐Ÿ‡ญ", name: "Thailand"}, - "TJ": {flag: "๐Ÿ‡น๐Ÿ‡ฏ", name: "Tajikistan"}, - "TK": {flag: "๐Ÿ‡น๐Ÿ‡ฐ", name: "Tokelau"}, - "TL": {flag: "๐Ÿ‡น๐Ÿ‡ฑ", name: "Timor-Leste"}, - "TM": {flag: "๐Ÿ‡น๐Ÿ‡ฒ", name: "Turkmenistan"}, - "TN": {flag: "๐Ÿ‡น๐Ÿ‡ณ", name: "Tunisia"}, - "TO": {flag: "๐Ÿ‡น๐Ÿ‡ด", name: "Tonga"}, - "TR": {flag: "๐Ÿ‡น๐Ÿ‡ท", name: "Turkey"}, - "TT": {flag: "๐Ÿ‡น๐Ÿ‡น", name: "Trinidad and Tobago"}, - "TV": {flag: "๐Ÿ‡น๐Ÿ‡ป", name: "Tuvalu"}, - "TW": {flag: "๐Ÿ‡น๐Ÿ‡ผ", name: "Taiwan"}, - "TZ": {flag: "๐Ÿ‡น๐Ÿ‡ฟ", name: "Tanzania"}, - "UA": {flag: "๐Ÿ‡บ๐Ÿ‡ฆ", name: "Ukraine"}, - "UG": {flag: "๐Ÿ‡บ๐Ÿ‡ฌ", name: "Uganda"}, - "UM": {flag: "๐Ÿ‡บ๐Ÿ‡ฒ", name: "United States Minor Outlying Islands"}, - "US": {flag: "๐Ÿ‡บ๐Ÿ‡ธ", name: "United States"}, - "UY": {flag: "๐Ÿ‡บ๐Ÿ‡พ", name: "Uruguay"}, - "UZ": {flag: "๐Ÿ‡บ๐Ÿ‡ฟ", name: "Uzbekistan"}, - "VA": {flag: "๐Ÿ‡ป๐Ÿ‡ฆ", name: "Vatican City"}, - "VC": {flag: "๐Ÿ‡ป๐Ÿ‡จ", name: "Saint Vincent and The Grenadines"}, - "VE": {flag: "๐Ÿ‡ป๐Ÿ‡ช", name: "Venezuela"}, - "VG": {flag: "๐Ÿ‡ป๐Ÿ‡ฌ", name: "Virgin Islands, British"}, - "VI": {flag: "๐Ÿ‡ป๐Ÿ‡ฎ", name: "Virgin Islands, U.S."}, - "VN": {flag: "๐Ÿ‡ป๐Ÿ‡ณ", name: "Viet Nam"}, - "VU": {flag: "๐Ÿ‡ป๐Ÿ‡บ", name: "Vanuatu"}, - "WF": {flag: "๐Ÿ‡ผ๐Ÿ‡ซ", name: "Wallis and Futuna"}, - "WS": {flag: "๐Ÿ‡ผ๐Ÿ‡ธ", name: "Samoa"}, - "YE": {flag: "๐Ÿ‡พ๐Ÿ‡ช", name: "Yemen"}, - "YT": {flag: "๐Ÿ‡พ๐Ÿ‡น", name: "Mayotte"}, - "ZA": {flag: "๐Ÿ‡ฟ๐Ÿ‡ฆ", name: "South Africa"}, - "ZM": {flag: "๐Ÿ‡ฟ๐Ÿ‡ฒ", name: "Zambia"}, - "ZW": {flag: "๐Ÿ‡ฟ๐Ÿ‡ผ", name: "Zimbabwe"} -} \ No newline at end of file + AD: { flag: "๐Ÿ‡ฆ๐Ÿ‡ฉ", name: "Andorra" }, + AE: { flag: "๐Ÿ‡ฆ๐Ÿ‡ช", name: "United Arab Emirates" }, + AF: { flag: "๐Ÿ‡ฆ๐Ÿ‡ซ", name: "Afghanistan" }, + AG: { flag: "๐Ÿ‡ฆ๐Ÿ‡ฌ", name: "Antigua and Barbuda" }, + AI: { flag: "๐Ÿ‡ฆ๐Ÿ‡ฎ", name: "Anguilla" }, + AL: { flag: "๐Ÿ‡ฆ๐Ÿ‡ฑ", name: "Albania" }, + AM: { flag: "๐Ÿ‡ฆ๐Ÿ‡ฒ", name: "Armenia" }, + AO: { flag: "๐Ÿ‡ฆ๐Ÿ‡ด", name: "Angola" }, + AQ: { flag: "๐Ÿ‡ฆ๐Ÿ‡ถ", name: "Antarctica" }, + AR: { flag: "๐Ÿ‡ฆ๐Ÿ‡ท", name: "Argentina" }, + AS: { flag: "๐Ÿ‡ฆ๐Ÿ‡ธ", name: "American Samoa" }, + AT: { flag: "๐Ÿ‡ฆ๐Ÿ‡น", name: "Austria" }, + AU: { flag: "๐Ÿ‡ฆ๐Ÿ‡บ", name: "Australia" }, + AW: { flag: "๐Ÿ‡ฆ๐Ÿ‡ผ", name: "Aruba" }, + AX: { flag: "๐Ÿ‡ฆ๐Ÿ‡ฝ", name: "ร…land Islands" }, + AZ: { flag: "๐Ÿ‡ฆ๐Ÿ‡ฟ", name: "Azerbaijan" }, + BA: { flag: "๐Ÿ‡ง๐Ÿ‡ฆ", name: "Bosnia and Herzegovina" }, + BB: { flag: "๐Ÿ‡ง๐Ÿ‡ง", name: "Barbados" }, + BD: { flag: "๐Ÿ‡ง๐Ÿ‡ฉ", name: "Bangladesh" }, + BE: { flag: "๐Ÿ‡ง๐Ÿ‡ช", name: "Belgium" }, + BF: { flag: "๐Ÿ‡ง๐Ÿ‡ซ", name: "Burkina Faso" }, + BG: { flag: "๐Ÿ‡ง๐Ÿ‡ฌ", name: "Bulgaria" }, + BH: { flag: "๐Ÿ‡ง๐Ÿ‡ญ", name: "Bahrain" }, + BI: { flag: "๐Ÿ‡ง๐Ÿ‡ฎ", name: "Burundi" }, + BJ: { flag: "๐Ÿ‡ง๐Ÿ‡ฏ", name: "Benin" }, + BL: { flag: "๐Ÿ‡ง๐Ÿ‡ฑ", name: "Saint Barthรฉlemy" }, + BM: { flag: "๐Ÿ‡ง๐Ÿ‡ฒ", name: "Bermuda" }, + BN: { flag: "๐Ÿ‡ง๐Ÿ‡ณ", name: "Brunei Darussalam" }, + BO: { flag: "๐Ÿ‡ง๐Ÿ‡ด", name: "Bolivia" }, + BQ: { flag: "๐Ÿ‡ง๐Ÿ‡ถ", name: "Bonaire, Sint Eustatius and Saba" }, + BR: { flag: "๐Ÿ‡ง๐Ÿ‡ท", name: "Brazil" }, + BS: { flag: "๐Ÿ‡ง๐Ÿ‡ธ", name: "Bahamas" }, + BT: { flag: "๐Ÿ‡ง๐Ÿ‡น", name: "Bhutan" }, + BV: { flag: "๐Ÿ‡ง๐Ÿ‡ป", name: "Bouvet Island" }, + BW: { flag: "๐Ÿ‡ง๐Ÿ‡ผ", name: "Botswana" }, + BY: { flag: "๐Ÿ‡ง๐Ÿ‡พ", name: "Belarus" }, + BZ: { flag: "๐Ÿ‡ง๐Ÿ‡ฟ", name: "Belize" }, + CA: { flag: "๐Ÿ‡จ๐Ÿ‡ฆ", name: "Canada" }, + CC: { flag: "๐Ÿ‡จ๐Ÿ‡จ", name: "Cocos (Keeling) Islands" }, + CD: { flag: "๐Ÿ‡จ๐Ÿ‡ฉ", name: "Congo" }, + CF: { flag: "๐Ÿ‡จ๐Ÿ‡ซ", name: "Central African Republic" }, + CG: { flag: "๐Ÿ‡จ๐Ÿ‡ฌ", name: "Congo" }, + CH: { flag: "๐Ÿ‡จ๐Ÿ‡ญ", name: "Switzerland" }, + CI: { flag: "๐Ÿ‡จ๐Ÿ‡ฎ", name: "Cรดte D'Ivoire" }, + CK: { flag: "๐Ÿ‡จ๐Ÿ‡ฐ", name: "Cook Islands" }, + CL: { flag: "๐Ÿ‡จ๐Ÿ‡ฑ", name: "Chile" }, + CM: { flag: "๐Ÿ‡จ๐Ÿ‡ฒ", name: "Cameroon" }, + CN: { flag: "๐Ÿ‡จ๐Ÿ‡ณ", name: "China" }, + CO: { flag: "๐Ÿ‡จ๐Ÿ‡ด", name: "Colombia" }, + CR: { flag: "๐Ÿ‡จ๐Ÿ‡ท", name: "Costa Rica" }, + CU: { flag: "๐Ÿ‡จ๐Ÿ‡บ", name: "Cuba" }, + CV: { flag: "๐Ÿ‡จ๐Ÿ‡ป", name: "Cape Verde" }, + CW: { flag: "๐Ÿ‡จ๐Ÿ‡ผ", name: "Curaรงao" }, + CX: { flag: "๐Ÿ‡จ๐Ÿ‡ฝ", name: "Christmas Island" }, + CY: { flag: "๐Ÿ‡จ๐Ÿ‡พ", name: "Cyprus" }, + CZ: { flag: "๐Ÿ‡จ๐Ÿ‡ฟ", name: "Czech Republic" }, + DE: { flag: "๐Ÿ‡ฉ๐Ÿ‡ช", name: "Germany" }, + DJ: { flag: "๐Ÿ‡ฉ๐Ÿ‡ฏ", name: "Djibouti" }, + DK: { flag: "๐Ÿ‡ฉ๐Ÿ‡ฐ", name: "Denmark" }, + DM: { flag: "๐Ÿ‡ฉ๐Ÿ‡ฒ", name: "Dominica" }, + DO: { flag: "๐Ÿ‡ฉ๐Ÿ‡ด", name: "Dominican Republic" }, + DZ: { flag: "๐Ÿ‡ฉ๐Ÿ‡ฟ", name: "Algeria" }, + EC: { flag: "๐Ÿ‡ช๐Ÿ‡จ", name: "Ecuador" }, + EE: { flag: "๐Ÿ‡ช๐Ÿ‡ช", name: "Estonia" }, + EG: { flag: "๐Ÿ‡ช๐Ÿ‡ฌ", name: "Egypt" }, + EH: { flag: "๐Ÿ‡ช๐Ÿ‡ญ", name: "Western Sahara" }, + ER: { flag: "๐Ÿ‡ช๐Ÿ‡ท", name: "Eritrea" }, + ES: { flag: "๐Ÿ‡ช๐Ÿ‡ธ", name: "Spain" }, + ET: { flag: "๐Ÿ‡ช๐Ÿ‡น", name: "Ethiopia" }, + FI: { flag: "๐Ÿ‡ซ๐Ÿ‡ฎ", name: "Finland" }, + FJ: { flag: "๐Ÿ‡ซ๐Ÿ‡ฏ", name: "Fiji" }, + FK: { flag: "๐Ÿ‡ซ๐Ÿ‡ฐ", name: "Falkland Islands (Malvinas)" }, + FM: { flag: "๐Ÿ‡ซ๐Ÿ‡ฒ", name: "Micronesia" }, + FO: { flag: "๐Ÿ‡ซ๐Ÿ‡ด", name: "Faroe Islands" }, + FR: { flag: "๐Ÿ‡ซ๐Ÿ‡ท", name: "France" }, + GA: { flag: "๐Ÿ‡ฌ๐Ÿ‡ฆ", name: "Gabon" }, + GB: { flag: "๐Ÿ‡ฌ๐Ÿ‡ง", name: "United Kingdom" }, + GD: { flag: "๐Ÿ‡ฌ๐Ÿ‡ฉ", name: "Grenada" }, + GE: { flag: "๐Ÿ‡ฌ๐Ÿ‡ช", name: "Georgia" }, + GF: { flag: "๐Ÿ‡ฌ๐Ÿ‡ซ", name: "French Guiana" }, + GG: { flag: "๐Ÿ‡ฌ๐Ÿ‡ฌ", name: "Guernsey" }, + GH: { flag: "๐Ÿ‡ฌ๐Ÿ‡ญ", name: "Ghana" }, + GI: { flag: "๐Ÿ‡ฌ๐Ÿ‡ฎ", name: "Gibraltar" }, + GL: { flag: "๐Ÿ‡ฌ๐Ÿ‡ฑ", name: "Greenland" }, + GM: { flag: "๐Ÿ‡ฌ๐Ÿ‡ฒ", name: "Gambia" }, + GN: { flag: "๐Ÿ‡ฌ๐Ÿ‡ณ", name: "Guinea" }, + GP: { flag: "๐Ÿ‡ฌ๐Ÿ‡ต", name: "Guadeloupe" }, + GQ: { flag: "๐Ÿ‡ฌ๐Ÿ‡ถ", name: "Equatorial Guinea" }, + GR: { flag: "๐Ÿ‡ฌ๐Ÿ‡ท", name: "Greece" }, + GS: { flag: "๐Ÿ‡ฌ๐Ÿ‡ธ", name: "South Georgia" }, + GT: { flag: "๐Ÿ‡ฌ๐Ÿ‡น", name: "Guatemala" }, + GU: { flag: "๐Ÿ‡ฌ๐Ÿ‡บ", name: "Guam" }, + GW: { flag: "๐Ÿ‡ฌ๐Ÿ‡ผ", name: "Guinea-Bissau" }, + GY: { flag: "๐Ÿ‡ฌ๐Ÿ‡พ", name: "Guyana" }, + HK: { flag: "๐Ÿ‡ญ๐Ÿ‡ฐ", name: "Hong Kong" }, + HM: { flag: "๐Ÿ‡ญ๐Ÿ‡ฒ", name: "Heard Island and Mcdonald Islands" }, + HN: { flag: "๐Ÿ‡ญ๐Ÿ‡ณ", name: "Honduras" }, + HR: { flag: "๐Ÿ‡ญ๐Ÿ‡ท", name: "Croatia" }, + HT: { flag: "๐Ÿ‡ญ๐Ÿ‡น", name: "Haiti" }, + HU: { flag: "๐Ÿ‡ญ๐Ÿ‡บ", name: "Hungary" }, + ID: { flag: "๐Ÿ‡ฎ๐Ÿ‡ฉ", name: "Indonesia" }, + IE: { flag: "๐Ÿ‡ฎ๐Ÿ‡ช", name: "Ireland" }, + IL: { flag: "๐Ÿ‡ฎ๐Ÿ‡ฑ", name: "Israel" }, + IM: { flag: "๐Ÿ‡ฎ๐Ÿ‡ฒ", name: "Isle of Man" }, + IN: { flag: "๐Ÿ‡ฎ๐Ÿ‡ณ", name: "India" }, + IO: { flag: "๐Ÿ‡ฎ๐Ÿ‡ด", name: "British Indian Ocean Territory" }, + IQ: { flag: "๐Ÿ‡ฎ๐Ÿ‡ถ", name: "Iraq" }, + IR: { flag: "๐Ÿ‡ฎ๐Ÿ‡ท", name: "Iran" }, + IS: { flag: "๐Ÿ‡ฎ๐Ÿ‡ธ", name: "Iceland" }, + IT: { flag: "๐Ÿ‡ฎ๐Ÿ‡น", name: "Italy" }, + JE: { flag: "๐Ÿ‡ฏ๐Ÿ‡ช", name: "Jersey" }, + JM: { flag: "๐Ÿ‡ฏ๐Ÿ‡ฒ", name: "Jamaica" }, + JO: { flag: "๐Ÿ‡ฏ๐Ÿ‡ด", name: "Jordan" }, + JP: { flag: "๐Ÿ‡ฏ๐Ÿ‡ต", name: "Japan" }, + KE: { flag: "๐Ÿ‡ฐ๐Ÿ‡ช", name: "Kenya" }, + KG: { flag: "๐Ÿ‡ฐ๐Ÿ‡ฌ", name: "Kyrgyzstan" }, + KH: { flag: "๐Ÿ‡ฐ๐Ÿ‡ญ", name: "Cambodia" }, + KI: { flag: "๐Ÿ‡ฐ๐Ÿ‡ฎ", name: "Kiribati" }, + KM: { flag: "๐Ÿ‡ฐ๐Ÿ‡ฒ", name: "Comoros" }, + KN: { flag: "๐Ÿ‡ฐ๐Ÿ‡ณ", name: "Saint Kitts and Nevis" }, + KP: { flag: "๐Ÿ‡ฐ๐Ÿ‡ต", name: "North Korea" }, + KR: { flag: "๐Ÿ‡ฐ๐Ÿ‡ท", name: "South Korea" }, + KW: { flag: "๐Ÿ‡ฐ๐Ÿ‡ผ", name: "Kuwait" }, + KY: { flag: "๐Ÿ‡ฐ๐Ÿ‡พ", name: "Cayman Islands" }, + KZ: { flag: "๐Ÿ‡ฐ๐Ÿ‡ฟ", name: "Kazakhstan" }, + LA: { flag: "๐Ÿ‡ฑ๐Ÿ‡ฆ", name: "Lao People's Democratic Republic" }, + LB: { flag: "๐Ÿ‡ฑ๐Ÿ‡ง", name: "Lebanon" }, + LC: { flag: "๐Ÿ‡ฑ๐Ÿ‡จ", name: "Saint Lucia" }, + LI: { flag: "๐Ÿ‡ฑ๐Ÿ‡ฎ", name: "Liechtenstein" }, + LK: { flag: "๐Ÿ‡ฑ๐Ÿ‡ฐ", name: "Sri Lanka" }, + LR: { flag: "๐Ÿ‡ฑ๐Ÿ‡ท", name: "Liberia" }, + LS: { flag: "๐Ÿ‡ฑ๐Ÿ‡ธ", name: "Lesotho" }, + LT: { flag: "๐Ÿ‡ฑ๐Ÿ‡น", name: "Lithuania" }, + LU: { flag: "๐Ÿ‡ฑ๐Ÿ‡บ", name: "Luxembourg" }, + LV: { flag: "๐Ÿ‡ฑ๐Ÿ‡ป", name: "Latvia" }, + LY: { flag: "๐Ÿ‡ฑ๐Ÿ‡พ", name: "Libya" }, + MA: { flag: "๐Ÿ‡ฒ๐Ÿ‡ฆ", name: "Morocco" }, + MC: { flag: "๐Ÿ‡ฒ๐Ÿ‡จ", name: "Monaco" }, + MD: { flag: "๐Ÿ‡ฒ๐Ÿ‡ฉ", name: "Moldova" }, + ME: { flag: "๐Ÿ‡ฒ๐Ÿ‡ช", name: "Montenegro" }, + MF: { flag: "๐Ÿ‡ฒ๐Ÿ‡ซ", name: "Saint Martin (French Part)" }, + MG: { flag: "๐Ÿ‡ฒ๐Ÿ‡ฌ", name: "Madagascar" }, + MH: { flag: "๐Ÿ‡ฒ๐Ÿ‡ญ", name: "Marshall Islands" }, + MK: { flag: "๐Ÿ‡ฒ๐Ÿ‡ฐ", name: "Macedonia" }, + ML: { flag: "๐Ÿ‡ฒ๐Ÿ‡ฑ", name: "Mali" }, + MM: { flag: "๐Ÿ‡ฒ๐Ÿ‡ฒ", name: "Myanmar" }, + MN: { flag: "๐Ÿ‡ฒ๐Ÿ‡ณ", name: "Mongolia" }, + MO: { flag: "๐Ÿ‡ฒ๐Ÿ‡ด", name: "Macao" }, + MP: { flag: "๐Ÿ‡ฒ๐Ÿ‡ต", name: "Northern Mariana Islands" }, + MQ: { flag: "๐Ÿ‡ฒ๐Ÿ‡ถ", name: "Martinique" }, + MR: { flag: "๐Ÿ‡ฒ๐Ÿ‡ท", name: "Mauritania" }, + MS: { flag: "๐Ÿ‡ฒ๐Ÿ‡ธ", name: "Montserrat" }, + MT: { flag: "๐Ÿ‡ฒ๐Ÿ‡น", name: "Malta" }, + MU: { flag: "๐Ÿ‡ฒ๐Ÿ‡บ", name: "Mauritius" }, + MV: { flag: "๐Ÿ‡ฒ๐Ÿ‡ป", name: "Maldives" }, + MW: { flag: "๐Ÿ‡ฒ๐Ÿ‡ผ", name: "Malawi" }, + MX: { flag: "๐Ÿ‡ฒ๐Ÿ‡ฝ", name: "Mexico" }, + MY: { flag: "๐Ÿ‡ฒ๐Ÿ‡พ", name: "Malaysia" }, + MZ: { flag: "๐Ÿ‡ฒ๐Ÿ‡ฟ", name: "Mozambique" }, + NA: { flag: "๐Ÿ‡ณ๐Ÿ‡ฆ", name: "Namibia" }, + NC: { flag: "๐Ÿ‡ณ๐Ÿ‡จ", name: "New Caledonia" }, + NE: { flag: "๐Ÿ‡ณ๐Ÿ‡ช", name: "Niger" }, + NF: { flag: "๐Ÿ‡ณ๐Ÿ‡ซ", name: "Norfolk Island" }, + NG: { flag: "๐Ÿ‡ณ๐Ÿ‡ฌ", name: "Nigeria" }, + NI: { flag: "๐Ÿ‡ณ๐Ÿ‡ฎ", name: "Nicaragua" }, + NL: { flag: "๐Ÿ‡ณ๐Ÿ‡ฑ", name: "Netherlands" }, + NO: { flag: "๐Ÿ‡ณ๐Ÿ‡ด", name: "Norway" }, + NP: { flag: "๐Ÿ‡ณ๐Ÿ‡ต", name: "Nepal" }, + NR: { flag: "๐Ÿ‡ณ๐Ÿ‡ท", name: "Nauru" }, + NU: { flag: "๐Ÿ‡ณ๐Ÿ‡บ", name: "Niue" }, + NZ: { flag: "๐Ÿ‡ณ๐Ÿ‡ฟ", name: "New Zealand" }, + OM: { flag: "๐Ÿ‡ด๐Ÿ‡ฒ", name: "Oman" }, + PA: { flag: "๐Ÿ‡ต๐Ÿ‡ฆ", name: "Panama" }, + PE: { flag: "๐Ÿ‡ต๐Ÿ‡ช", name: "Peru" }, + PF: { flag: "๐Ÿ‡ต๐Ÿ‡ซ", name: "French Polynesia" }, + PG: { flag: "๐Ÿ‡ต๐Ÿ‡ฌ", name: "Papua New Guinea" }, + PH: { flag: "๐Ÿ‡ต๐Ÿ‡ญ", name: "Philippines" }, + PK: { flag: "๐Ÿ‡ต๐Ÿ‡ฐ", name: "Pakistan" }, + PL: { flag: "๐Ÿ‡ต๐Ÿ‡ฑ", name: "Poland" }, + PM: { flag: "๐Ÿ‡ต๐Ÿ‡ฒ", name: "Saint Pierre and Miquelon" }, + PN: { flag: "๐Ÿ‡ต๐Ÿ‡ณ", name: "Pitcairn" }, + PR: { flag: "๐Ÿ‡ต๐Ÿ‡ท", name: "Puerto Rico" }, + PS: { flag: "๐Ÿ‡ต๐Ÿ‡ธ", name: "Palestinian Territory" }, + PT: { flag: "๐Ÿ‡ต๐Ÿ‡น", name: "Portugal" }, + PW: { flag: "๐Ÿ‡ต๐Ÿ‡ผ", name: "Palau" }, + PY: { flag: "๐Ÿ‡ต๐Ÿ‡พ", name: "Paraguay" }, + QA: { flag: "๐Ÿ‡ถ๐Ÿ‡ฆ", name: "Qatar" }, + RE: { flag: "๐Ÿ‡ท๐Ÿ‡ช", name: "Rรฉunion" }, + RO: { flag: "๐Ÿ‡ท๐Ÿ‡ด", name: "Romania" }, + RS: { flag: "๐Ÿ‡ท๐Ÿ‡ธ", name: "Serbia" }, + RU: { flag: "๐Ÿ‡ท๐Ÿ‡บ", name: "Russia" }, + RW: { flag: "๐Ÿ‡ท๐Ÿ‡ผ", name: "Rwanda" }, + SA: { flag: "๐Ÿ‡ธ๐Ÿ‡ฆ", name: "Saudi Arabia" }, + SB: { flag: "๐Ÿ‡ธ๐Ÿ‡ง", name: "Solomon Islands" }, + SC: { flag: "๐Ÿ‡ธ๐Ÿ‡จ", name: "Seychelles" }, + SD: { flag: "๐Ÿ‡ธ๐Ÿ‡ฉ", name: "Sudan" }, + SE: { flag: "๐Ÿ‡ธ๐Ÿ‡ช", name: "Sweden" }, + SG: { flag: "๐Ÿ‡ธ๐Ÿ‡ฌ", name: "Singapore" }, + SH: { flag: "๐Ÿ‡ธ๐Ÿ‡ญ", name: "Saint Helena, Ascension and Tristan Da Cunha" }, + SI: { flag: "๐Ÿ‡ธ๐Ÿ‡ฎ", name: "Slovenia" }, + SJ: { flag: "๐Ÿ‡ธ๐Ÿ‡ฏ", name: "Svalbard and Jan Mayen" }, + SK: { flag: "๐Ÿ‡ธ๐Ÿ‡ฐ", name: "Slovakia" }, + SL: { flag: "๐Ÿ‡ธ๐Ÿ‡ฑ", name: "Sierra Leone" }, + SM: { flag: "๐Ÿ‡ธ๐Ÿ‡ฒ", name: "San Marino" }, + SN: { flag: "๐Ÿ‡ธ๐Ÿ‡ณ", name: "Senegal" }, + SO: { flag: "๐Ÿ‡ธ๐Ÿ‡ด", name: "Somalia" }, + SR: { flag: "๐Ÿ‡ธ๐Ÿ‡ท", name: "Suriname" }, + SS: { flag: "๐Ÿ‡ธ๐Ÿ‡ธ", name: "South Sudan" }, + ST: { flag: "๐Ÿ‡ธ๐Ÿ‡น", name: "Sao Tome and Principe" }, + SV: { flag: "๐Ÿ‡ธ๐Ÿ‡ป", name: "El Salvador" }, + SX: { flag: "๐Ÿ‡ธ๐Ÿ‡ฝ", name: "Sint Maarten (Dutch Part)" }, + SY: { flag: "๐Ÿ‡ธ๐Ÿ‡พ", name: "Syrian Arab Republic" }, + SZ: { flag: "๐Ÿ‡ธ๐Ÿ‡ฟ", name: "Swaziland" }, + TC: { flag: "๐Ÿ‡น๐Ÿ‡จ", name: "Turks and Caicos Islands" }, + TD: { flag: "๐Ÿ‡น๐Ÿ‡ฉ", name: "Chad" }, + TF: { flag: "๐Ÿ‡น๐Ÿ‡ซ", name: "French Southern Territories" }, + TG: { flag: "๐Ÿ‡น๐Ÿ‡ฌ", name: "Togo" }, + TH: { flag: "๐Ÿ‡น๐Ÿ‡ญ", name: "Thailand" }, + TJ: { flag: "๐Ÿ‡น๐Ÿ‡ฏ", name: "Tajikistan" }, + TK: { flag: "๐Ÿ‡น๐Ÿ‡ฐ", name: "Tokelau" }, + TL: { flag: "๐Ÿ‡น๐Ÿ‡ฑ", name: "Timor-Leste" }, + TM: { flag: "๐Ÿ‡น๐Ÿ‡ฒ", name: "Turkmenistan" }, + TN: { flag: "๐Ÿ‡น๐Ÿ‡ณ", name: "Tunisia" }, + TO: { flag: "๐Ÿ‡น๐Ÿ‡ด", name: "Tonga" }, + TR: { flag: "๐Ÿ‡น๐Ÿ‡ท", name: "Turkey" }, + TT: { flag: "๐Ÿ‡น๐Ÿ‡น", name: "Trinidad and Tobago" }, + TV: { flag: "๐Ÿ‡น๐Ÿ‡ป", name: "Tuvalu" }, + TW: { flag: "๐Ÿ‡น๐Ÿ‡ผ", name: "Taiwan" }, + TZ: { flag: "๐Ÿ‡น๐Ÿ‡ฟ", name: "Tanzania" }, + UA: { flag: "๐Ÿ‡บ๐Ÿ‡ฆ", name: "Ukraine" }, + UG: { flag: "๐Ÿ‡บ๐Ÿ‡ฌ", name: "Uganda" }, + UM: { flag: "๐Ÿ‡บ๐Ÿ‡ฒ", name: "United States Minor Outlying Islands" }, + US: { flag: "๐Ÿ‡บ๐Ÿ‡ธ", name: "United States" }, + UY: { flag: "๐Ÿ‡บ๐Ÿ‡พ", name: "Uruguay" }, + UZ: { flag: "๐Ÿ‡บ๐Ÿ‡ฟ", name: "Uzbekistan" }, + VA: { flag: "๐Ÿ‡ป๐Ÿ‡ฆ", name: "Vatican City" }, + VC: { flag: "๐Ÿ‡ป๐Ÿ‡จ", name: "Saint Vincent and The Grenadines" }, + VE: { flag: "๐Ÿ‡ป๐Ÿ‡ช", name: "Venezuela" }, + VG: { flag: "๐Ÿ‡ป๐Ÿ‡ฌ", name: "Virgin Islands, British" }, + VI: { flag: "๐Ÿ‡ป๐Ÿ‡ฎ", name: "Virgin Islands, U.S." }, + VN: { flag: "๐Ÿ‡ป๐Ÿ‡ณ", name: "Viet Nam" }, + VU: { flag: "๐Ÿ‡ป๐Ÿ‡บ", name: "Vanuatu" }, + WF: { flag: "๐Ÿ‡ผ๐Ÿ‡ซ", name: "Wallis and Futuna" }, + WS: { flag: "๐Ÿ‡ผ๐Ÿ‡ธ", name: "Samoa" }, + YE: { flag: "๐Ÿ‡พ๐Ÿ‡ช", name: "Yemen" }, + YT: { flag: "๐Ÿ‡พ๐Ÿ‡น", name: "Mayotte" }, + ZA: { flag: "๐Ÿ‡ฟ๐Ÿ‡ฆ", name: "South Africa" }, + ZM: { flag: "๐Ÿ‡ฟ๐Ÿ‡ฒ", name: "Zambia" }, + ZW: { flag: "๐Ÿ‡ฟ๐Ÿ‡ผ", name: "Zimbabwe" } +}; diff --git a/ui/src/index.css b/ui/src/index.css index ec2585e..8285d2a 100644 --- a/ui/src/index.css +++ b/ui/src/index.css @@ -1,13 +1,10 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } diff --git a/ui/src/index.js b/ui/src/index.js index da56e89..e77529f 100644 --- a/ui/src/index.js +++ b/ui/src/index.js @@ -1,7 +1,7 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import './index.css'; -import App from './App'; +import React from "react"; +import ReactDOM from "react-dom"; +import "./index.css"; +import App from "./App"; import { BrowserRouter } from "react-router-dom"; ReactDOM.render( @@ -10,5 +10,5 @@ ReactDOM.render( , - document.getElementById('root') -); \ No newline at end of file + document.getElementById("root") +); diff --git a/ui/src/util.js b/ui/src/util.js index eedc05f..f0262ad 100644 --- a/ui/src/util.js +++ b/ui/src/util.js @@ -1,81 +1,90 @@ -import axios from 'axios' -import {useEffect, useState, useRef, Component, useCallback} from 'react'; -import { useSearchParams } from 'react-router-dom'; +import axios from "axios"; +import { useEffect, useState, useRef, Component, useCallback } from "react"; +import { useSearchParams } from "react-router-dom"; export const http = axios.create({ - baseURL: "/api", + baseURL: "/api" }); export class ErrorBoundary extends Component { - state = { error: false, errorMessage: "" }; - - static getDerivedStateFromError(error) { - return { error: true, errorMessage: error.toString() } - }; - - componentDidCatch(error, _) { - console.error(error) - } - - render() { - if (this.state.error) { - return
-

Failed

- {this.state.errorMessage} -
- } - return this.props.children - } + state = { error: false, errorMessage: "" }; + + static getDerivedStateFromError(error) { + return { error: true, errorMessage: error.toString() }; + } + + componentDidCatch(error, _) { + console.error(error); + } + + render() { + if (this.state.error) { + return ( +
+

Failed

+ {this.state.errorMessage} +
+ ); + } + return this.props.children; + } } -export function TimeDiff({ts, title}) { - const now = new Date() - const it = new Date(ts) - let elapsed = Math.abs((now - it) / 1000) - let value = '?' +export function TimeDiff({ ts, title }) { + const now = new Date(); + const it = new Date(ts); + let elapsed = Math.abs((now - it) / 1000); + let value = "?"; if (elapsed < 60) { - value = `${elapsed.toFixed()}s` - } else if (elapsed < 60*60) { - value = `${(elapsed/60).toFixed()}m` - } else if (elapsed < 60*60*24) { - value = `${(elapsed/60/60).toFixed()}h` - } else if (elapsed < 60*60*24*7) { - value = `${(elapsed/60/60/24).toFixed()}d` - } else if (elapsed < 60*60*24*30) { - value = `${(elapsed/60/60/24/7).toFixed()}w` + value = `${elapsed.toFixed()}s`; + } else if (elapsed < 60 * 60) { + value = `${(elapsed / 60).toFixed()}m`; + } else if (elapsed < 60 * 60 * 24) { + value = `${(elapsed / 60 / 60).toFixed()}h`; + } else if (elapsed < 60 * 60 * 24 * 7) { + value = `${(elapsed / 60 / 60 / 24).toFixed()}d`; + } else if (elapsed < 60 * 60 * 24 * 30) { + value = `${(elapsed / 60 / 60 / 24 / 7).toFixed()}w`; + } + if (it > now) { + return ( + + in {value} + + ); } - if (it > now) { - return in {value} - } - return {value} ago + return ( + + {value} ago + + ); } export function IconHeader({ icon, col, title }) { - const cl = `bi bi-${icon}` - return
+ const cl = `bi bi-${icon}`; + return ( + + ); } export function Card({ label, value, increment = 0 }) { - return ( -
-
-
-
-
-
- {label} -
- - {value} - - {increment > 0 && - +{increment}} -
-
-
-
-
- ); + return ( +
+
+
+
+
+
{label}
+ {value} + {increment > 0 && +{increment}} +
+
+
+
+
+ ); } export function LiveFilter({ endpoint, onUpdate, minDelay = 5000 }) { @@ -86,134 +95,157 @@ export function LiveFilter({ endpoint, onUpdate, minDelay = 5000 }) { const [searchParams, setSearchParams] = useSearchParams(); let doFilter = useCallback(() => { - clearTimeout(savedCallback.current) + clearTimeout(savedCallback.current); savedCallback.current = setTimeout(() => { - http.get(endpoint, {params: searchParams}).then(response => { - if (pause) { - clearTimeout(savedCallback.current) - return - } - setTotal(response.data.Total) - onUpdate(response.data) - setFailure(null) - savedCallback.current = setTimeout(doFilter, minDelay) - }).catch(err => { - if (err.isAxiosError) { - setFailure(err.response.data.Message) - } - clearTimeout(savedCallback.current) - return false - }) - }, 500) - }, [pause, savedCallback, searchParams, endpoint, minDelay, onUpdate]) + http + .get(endpoint, { params: searchParams }) + .then(response => { + if (pause) { + clearTimeout(savedCallback.current); + return; + } + setTotal(response.data.Total); + onUpdate(response.data); + setFailure(null); + savedCallback.current = setTimeout(doFilter, minDelay); + }) + .catch(err => { + if (err.isAxiosError) { + setFailure(err.response.data.Message); + } + clearTimeout(savedCallback.current); + return false; + }); + }, 500); + }, [pause, savedCallback, searchParams, endpoint, minDelay, onUpdate]); useEffect(() => { - doFilter() - return () => clearTimeout(savedCallback.current) + doFilter(); + return () => clearTimeout(savedCallback.current); }, [savedCallback, doFilter]); - let filter = searchParams.get("filter") || "" + let filter = searchParams.get("filter") || ""; let change = event => { - filter = event.target.value - setSearchParams(filter === "" ? {} : { filter }) - doFilter() - } + filter = event.target.value; + setSearchParams(filter === "" ? {} : { filter }); + doFilter(); + }; let togglePause = () => { - setPause(!pause) + setPause(!pause); if (pause) { - doFilter() + doFilter(); } else { - clearTimeout(savedCallback.current) + clearTimeout(savedCallback.current); } - } + }; return ( -
-
+
+
- {total != null && {total} total} - + {total != null && {total} total} +
-
- {failure != null &&
{failure}
} + {failure != null && ( +
+ {failure} +
+ )}
- ) - + ); } -function FilterableFacet({Name, Value, link}) { - const short = Name.length > 32 ? `${Name.substring(0, 32)}...` : Name - return
  • - {link === null ? short : - {short} - } {Value} -
  • +function FilterableFacet({ Name, Value, link }) { + const short = Name.length > 32 ? `${Name.substring(0, 32)}...` : Name; + return ( +
  • + {link === null ? ( + short + ) : ( + + {short} + + )}{" "} + {Value} +
  • + ); } -export function SearchFacet({name, items, link = null}) { - let result = [] +export function SearchFacet({ name, items, link = null }) { + let result = []; if (items.length > 1) { - result.push(
    - {name} -
      - {items.map(f => )} -
    -
    ) + result.push( +
    + {name} +
      + {items.map(f => ( + + ))} +
    +
    + ); } - return result + return result; } -function QueryFacetFilter({Name, Value, Filter, endpoint}) { - const short = Name.length > 32 ? `${Name.substring(0, 32)}...` : Name - const link = Name !== "n/a" ? `${endpoint}?filter=${Filter}` : null - return
  • - {link === null ? short : - {short} - } {Value} -
  • +function QueryFacetFilter({ Name, Value, Filter, endpoint }) { + const short = Name.length > 32 ? `${Name.substring(0, 32)}...` : Name; + const link = Name !== "n/a" ? `${endpoint}?filter=${Filter}` : null; + return ( +
  • + {link === null ? ( + short + ) : ( + + {short} + + )}{" "} + {Value} +
  • + ); } -function QueryFacet({Name, Top, endpoint}) { - let result = [] +function QueryFacet({ Name, Top, endpoint }) { + let result = []; if (Top.length > 1) { - result.push(
    - {Name} -
      - {Top.map(f => - )} -
    -
    ) + result.push( +
    + {Name} +
      + {Top.map(f => ( + + ))} +
    +
    + ); } - return result + return result; } -export function QueryFacets({Facets, endpoint}) { - return Facets != null && Facets.map(f => - ) +export function QueryFacets({ Facets, endpoint }) { + return Facets != null && Facets.map(f => ); } export function useInterval(callback, delay) { - // https://overreacted.io/making-setinterval-declarative-with-react-hooks/ - const savedCallback = useRef(); - useEffect(() => { - savedCallback.current = callback; - }); - useEffect(() => { - function tick() { - savedCallback.current(); - } - if (delay !== null) { - let id = setInterval(tick, delay); - return () => clearInterval(id); - } - }, [delay]); + // https://overreacted.io/making-setinterval-declarative-with-react-hooks/ + const savedCallback = useRef(); + useEffect(() => { + savedCallback.current = callback; + }); + useEffect(() => { + function tick() { + savedCallback.current(); + } + if (delay !== null) { + let id = setInterval(tick, delay); + return () => clearInterval(id); + } + }, [delay]); } export function useTitle(title) { From 671e4c57cd9dfab65d383b9a50d350147f4c4e25 Mon Sep 17 00:00:00 2001 From: Ar-Kan Date: Sat, 17 Jun 2023 14:23:33 -0300 Subject: [PATCH 4/5] Update scripts --- ui/package.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ui/package.json b/ui/package.json index ddea794..6ff597e 100644 --- a/ui/package.json +++ b/ui/package.json @@ -15,10 +15,9 @@ "react-scripts": "^5.0.0" }, "scripts": { - "start": "node_modules/react-scripts/bin/react-scripts.js start", - "build": "node_modules/react-scripts/bin/react-scripts.js build", - "test": "node_modules/react-scripts/bin/react-scripts.js test", - "eject": "node_modules/react-scripts/bin/react-scripts.js eject", + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", "prettier": "npx prettier --write ." }, "eslintConfig": { From b11d2d27045b9b0a8f722291f5f3e275edd2d5fa Mon Sep 17 00:00:00 2001 From: Ar-Kan Date: Sat, 17 Jun 2023 14:56:33 -0300 Subject: [PATCH 5/5] Rollback .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8db218f..f1dd4cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ vendor main __debug_bin -.idea ui/build
    {tinyNum(props[col])}{props[col]}{successRate(props).toFixed(2)}%{tinyNum(props[col])} + {tinyNum(props[col])} + + {props[col]} + + {successRate(props).toFixed(2)}% + + {tinyNum(props[col])} +
    - {icons[State]}  - {Name}  - {refresh} -
    + {icons[State]}  + + {Name} + +   + + {refresh} + +
    + +