diff --git a/README.md b/.github/README.md similarity index 96% rename from README.md rename to .github/README.md index 33968fe..15483c4 100644 --- a/README.md +++ b/.github/README.md @@ -1,6 +1,6 @@

- +

@@ -28,7 +28,7 @@ - [ ] [Persian](https://github.com/victor-savinov/user-agent/tree/master/_locales/fa/messages.json) `/fa/` - [ ] [Finnish](https://github.com/victor-savinov/user-agent/tree/master/_locales/fi/messages.json) `/fi/` - [ ] [Filipino](https://github.com/victor-savinov/user-agent/tree/master/_locales/fil/messages.json) `/fil/` -- [ ] [French](https://github.com/victor-savinov/user-agent/tree/master/_locales/fr/messages.json) `/fr/` +- [x] [French](https://github.com/victor-savinov/user-agent/tree/master/_locales/fr/messages.json) `/fr/` - [ ] [Gujarati](https://github.com/victor-savinov/user-agent/tree/master/_locales/gu/messages.json) `/gu/` - [ ] [Hebrew](https://github.com/victor-savinov/user-agent/tree/master/_locales/he/messages.json) `/he/` - [ ] [Hindi](https://github.com/victor-savinov/user-agent/tree/master/_locales/hi/messages.json) `/hi/` @@ -63,4 +63,4 @@ - [ ] [Ukrainian](https://github.com/victor-savinov/user-agent/tree/master/_locales/uk/messages.json) `/uk/` - [ ] [Vietnamese](https://github.com/victor-savinov/user-agent/tree/master/_locales/vi/messages.json) `/vi/` - [ ] [Chinese (China)](https://github.com/victor-savinov/user-agent/tree/master/_locales/zh_CN/messages.json) `/zh_CN/` -- [ ] [Chinese (Taiwan)](https://github.com/victor-savinov/user-agent/tree/master/_locales/zh_TW/messages.json) `/zh_TW/` +- [ ] [Chinese (Taiwan)](https://github.com/victor-savinov/user-agent/tree/master/_locales/zh_TW/messages.json) `/zh_TW/` \ No newline at end of file diff --git a/_locales/am/messages.json b/_locales/am/messages.json index d03d442..c39c031 100644 --- a/_locales/am/messages.json +++ b/_locales/am/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/ar/messages.json b/_locales/ar/messages.json index d03d442..c39c031 100644 --- a/_locales/ar/messages.json +++ b/_locales/ar/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/bg/messages.json b/_locales/bg/messages.json index d03d442..c39c031 100644 --- a/_locales/bg/messages.json +++ b/_locales/bg/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/bn/messages.json b/_locales/bn/messages.json index d03d442..c39c031 100644 --- a/_locales/bn/messages.json +++ b/_locales/bn/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/ca/messages.json b/_locales/ca/messages.json index d03d442..c39c031 100644 --- a/_locales/ca/messages.json +++ b/_locales/ca/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/cs/messages.json b/_locales/cs/messages.json index d03d442..c39c031 100644 --- a/_locales/cs/messages.json +++ b/_locales/cs/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/da/messages.json b/_locales/da/messages.json index d03d442..c39c031 100644 --- a/_locales/da/messages.json +++ b/_locales/da/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/de/messages.json b/_locales/de/messages.json index fc973ca..46c2dbb 100644 --- a/_locales/de/messages.json +++ b/_locales/de/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/el/messages.json b/_locales/el/messages.json index d03d442..c39c031 100644 --- a/_locales/el/messages.json +++ b/_locales/el/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/en/messages.json b/_locales/en/messages.json index d03d442..c39c031 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/es/messages.json b/_locales/es/messages.json index d03d442..c39c031 100644 --- a/_locales/es/messages.json +++ b/_locales/es/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/et/messages.json b/_locales/et/messages.json index d03d442..c39c031 100644 --- a/_locales/et/messages.json +++ b/_locales/et/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/fa/messages.json b/_locales/fa/messages.json index d03d442..c39c031 100644 --- a/_locales/fa/messages.json +++ b/_locales/fa/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/fi/messages.json b/_locales/fi/messages.json index d03d442..c39c031 100644 --- a/_locales/fi/messages.json +++ b/_locales/fi/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/fil/messages.json b/_locales/fil/messages.json index d03d442..c39c031 100644 --- a/_locales/fil/messages.json +++ b/_locales/fil/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json index e5ef77d..a4e9bc1 100644 --- a/_locales/fr/messages.json +++ b/_locales/fr/messages.json @@ -2,6 +2,9 @@ "about": { "message": "À propos" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Apparence" }, @@ -11,6 +14,9 @@ "browser": { "message": "Navigateur web" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Voiture" }, @@ -26,6 +32,9 @@ "device": { "message": "Appareil" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Cacher \"Nous partager...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Langue" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Écran" }, @@ -95,4 +110,4 @@ "watch": { "message": "Montre" } -} +} \ No newline at end of file diff --git a/_locales/gu/messages.json b/_locales/gu/messages.json index d03d442..c39c031 100644 --- a/_locales/gu/messages.json +++ b/_locales/gu/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/he/messages.json b/_locales/he/messages.json index d03d442..c39c031 100644 --- a/_locales/he/messages.json +++ b/_locales/he/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/hi/messages.json b/_locales/hi/messages.json index d03d442..c39c031 100644 --- a/_locales/hi/messages.json +++ b/_locales/hi/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/hin/messages.json b/_locales/hin/messages.json new file mode 100644 index 0000000..c39c031 --- /dev/null +++ b/_locales/hin/messages.json @@ -0,0 +1,113 @@ +{ + "about": { + "message": "About" + }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, + "appearance": { + "message": "Appearance" + }, + "audioFormats": { + "message": "Audio formats" + }, + "browser": { + "message": "Browser" + }, + "cancel": { + "message": "Cancel" + }, + "car": { + "message": "Car" + }, + "computer": { + "message": "Computer" + }, + "cores": { + "message": "Cores" + }, + "custom": { + "message": "Custom" + }, + "device": { + "message": "Device" + }, + "export": { + "message": "Export" + }, + "extension": { + "message": "Extension" + }, + "flash": { + "message": "Flash" + }, + "gameConsole": { + "message": "Game console" + }, + "gpu": { + "message": "GPU" + }, + "hardware": { + "message": "Hardware" + }, + "hideStarUs": { + "message": "Hide \"Star us...\"" + }, + "import": { + "message": "Import" + }, + "language": { + "message": "Language" + }, + "languages": { + "message": "Languages" + }, + "name": { + "message": "Name" + }, + "os": { + "message": "OS" + }, + "permissions": { + "message": "Permissions" + }, + "phone": { + "message": "Phone" + }, + "platform": { + "message": "Platform" + }, + "ram": { + "message": "RAM" + }, + "reset": { + "message": "Reset" + }, + "screen": { + "message": "Screen" + }, + "settings": { + "message": "Settings" + }, + "software": { + "message": "Software" + }, + "tablet": { + "message": "Tablet" + }, + "tv": { + "message": "TV" + }, + "type": { + "message": "Type" + }, + "version": { + "message": "Version" + }, + "videoFormats": { + "message": "Video formats" + }, + "watch": { + "message": "Watch" + } +} \ No newline at end of file diff --git a/_locales/hr/messages.json b/_locales/hr/messages.json index d03d442..c39c031 100644 --- a/_locales/hr/messages.json +++ b/_locales/hr/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/hu/messages.json b/_locales/hu/messages.json index d03d442..c39c031 100644 --- a/_locales/hu/messages.json +++ b/_locales/hu/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/id/messages.json b/_locales/id/messages.json index d03d442..c39c031 100644 --- a/_locales/id/messages.json +++ b/_locales/id/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/it/messages.json b/_locales/it/messages.json index d03d442..c39c031 100644 --- a/_locales/it/messages.json +++ b/_locales/it/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json index d03d442..c39c031 100644 --- a/_locales/ja/messages.json +++ b/_locales/ja/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/kn/messages.json b/_locales/kn/messages.json index d03d442..c39c031 100644 --- a/_locales/kn/messages.json +++ b/_locales/kn/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/ko/messages.json b/_locales/ko/messages.json index d03d442..c39c031 100644 --- a/_locales/ko/messages.json +++ b/_locales/ko/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/lt/messages.json b/_locales/lt/messages.json index d03d442..c39c031 100644 --- a/_locales/lt/messages.json +++ b/_locales/lt/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/lv/messages.json b/_locales/lv/messages.json index d03d442..c39c031 100644 --- a/_locales/lv/messages.json +++ b/_locales/lv/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/ml/messages.json b/_locales/ml/messages.json index d03d442..c39c031 100644 --- a/_locales/ml/messages.json +++ b/_locales/ml/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/mr/messages.json b/_locales/mr/messages.json index d03d442..c39c031 100644 --- a/_locales/mr/messages.json +++ b/_locales/mr/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/ms/messages.json b/_locales/ms/messages.json index d03d442..c39c031 100644 --- a/_locales/ms/messages.json +++ b/_locales/ms/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/nb_NO/messages.json b/_locales/nb_NO/messages.json new file mode 100644 index 0000000..c39c031 --- /dev/null +++ b/_locales/nb_NO/messages.json @@ -0,0 +1,113 @@ +{ + "about": { + "message": "About" + }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, + "appearance": { + "message": "Appearance" + }, + "audioFormats": { + "message": "Audio formats" + }, + "browser": { + "message": "Browser" + }, + "cancel": { + "message": "Cancel" + }, + "car": { + "message": "Car" + }, + "computer": { + "message": "Computer" + }, + "cores": { + "message": "Cores" + }, + "custom": { + "message": "Custom" + }, + "device": { + "message": "Device" + }, + "export": { + "message": "Export" + }, + "extension": { + "message": "Extension" + }, + "flash": { + "message": "Flash" + }, + "gameConsole": { + "message": "Game console" + }, + "gpu": { + "message": "GPU" + }, + "hardware": { + "message": "Hardware" + }, + "hideStarUs": { + "message": "Hide \"Star us...\"" + }, + "import": { + "message": "Import" + }, + "language": { + "message": "Language" + }, + "languages": { + "message": "Languages" + }, + "name": { + "message": "Name" + }, + "os": { + "message": "OS" + }, + "permissions": { + "message": "Permissions" + }, + "phone": { + "message": "Phone" + }, + "platform": { + "message": "Platform" + }, + "ram": { + "message": "RAM" + }, + "reset": { + "message": "Reset" + }, + "screen": { + "message": "Screen" + }, + "settings": { + "message": "Settings" + }, + "software": { + "message": "Software" + }, + "tablet": { + "message": "Tablet" + }, + "tv": { + "message": "TV" + }, + "type": { + "message": "Type" + }, + "version": { + "message": "Version" + }, + "videoFormats": { + "message": "Video formats" + }, + "watch": { + "message": "Watch" + } +} \ No newline at end of file diff --git a/_locales/nl/messages.json b/_locales/nl/messages.json index d03d442..c39c031 100644 --- a/_locales/nl/messages.json +++ b/_locales/nl/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/no/messages.json b/_locales/no/messages.json index d03d442..c39c031 100644 --- a/_locales/no/messages.json +++ b/_locales/no/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/pl/messages.json b/_locales/pl/messages.json index d03d442..c39c031 100644 --- a/_locales/pl/messages.json +++ b/_locales/pl/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/pt_BR/messages.json b/_locales/pt_BR/messages.json index d03d442..c39c031 100644 --- a/_locales/pt_BR/messages.json +++ b/_locales/pt_BR/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/pt_PT/messages.json b/_locales/pt_PT/messages.json index d03d442..c39c031 100644 --- a/_locales/pt_PT/messages.json +++ b/_locales/pt_PT/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/ro/messages.json b/_locales/ro/messages.json index d03d442..c39c031 100644 --- a/_locales/ro/messages.json +++ b/_locales/ro/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/ru/messages.json b/_locales/ru/messages.json index f9d0a8d..f86d114 100644 --- a/_locales/ru/messages.json +++ b/_locales/ru/messages.json @@ -2,6 +2,9 @@ "about": { "message": "О системе" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "Все ваши настройки будут удалены и не могут быть восстановлены" + }, "appearance": { "message": "Внешний вид" }, @@ -11,6 +14,9 @@ "browser": { "message": "Браузер" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Автомобиль" }, @@ -26,6 +32,9 @@ "device": { "message": "Устройство" }, + "export": { + "message": "Экспортировать" + }, "extension": { "message": "Расширение" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Скрыть \"Star us...\"" }, + "import": { + "message": "Импортировать" + }, "language": { "message": "Язык" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Сбросить" + }, "screen": { "message": "Экран" }, diff --git a/_locales/sk/messages.json b/_locales/sk/messages.json index d03d442..c39c031 100644 --- a/_locales/sk/messages.json +++ b/_locales/sk/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/sl/messages.json b/_locales/sl/messages.json index d03d442..c39c031 100644 --- a/_locales/sl/messages.json +++ b/_locales/sl/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/sr/messages.json b/_locales/sr/messages.json index d03d442..c39c031 100644 --- a/_locales/sr/messages.json +++ b/_locales/sr/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index d03d442..c39c031 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/sw/messages.json b/_locales/sw/messages.json index d03d442..c39c031 100644 --- a/_locales/sw/messages.json +++ b/_locales/sw/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/ta/messages.json b/_locales/ta/messages.json index d03d442..c39c031 100644 --- a/_locales/ta/messages.json +++ b/_locales/ta/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/te/messages.json b/_locales/te/messages.json index d03d442..c39c031 100644 --- a/_locales/te/messages.json +++ b/_locales/te/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/th/messages.json b/_locales/th/messages.json index d03d442..c39c031 100644 --- a/_locales/th/messages.json +++ b/_locales/th/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/tr/messages.json b/_locales/tr/messages.json index d03d442..c39c031 100644 --- a/_locales/tr/messages.json +++ b/_locales/tr/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/uk/messages.json b/_locales/uk/messages.json index d03d442..c39c031 100644 --- a/_locales/uk/messages.json +++ b/_locales/uk/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/vi/messages.json b/_locales/vi/messages.json index d03d442..c39c031 100644 --- a/_locales/vi/messages.json +++ b/_locales/vi/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/zh_CN/messages.json b/_locales/zh_CN/messages.json index d03d442..c39c031 100644 --- a/_locales/zh_CN/messages.json +++ b/_locales/zh_CN/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/_locales/zh_TW/messages.json b/_locales/zh_TW/messages.json index d03d442..c39c031 100644 --- a/_locales/zh_TW/messages.json +++ b/_locales/zh_TW/messages.json @@ -2,6 +2,9 @@ "about": { "message": "About" }, + "allYourSettingsWillBeErasedAndCanTBeRecovered": { + "message": "All your settings will be erased and can't be recovered" + }, "appearance": { "message": "Appearance" }, @@ -11,6 +14,9 @@ "browser": { "message": "Browser" }, + "cancel": { + "message": "Cancel" + }, "car": { "message": "Car" }, @@ -26,6 +32,9 @@ "device": { "message": "Device" }, + "export": { + "message": "Export" + }, "extension": { "message": "Extension" }, @@ -44,6 +53,9 @@ "hideStarUs": { "message": "Hide \"Star us...\"" }, + "import": { + "message": "Import" + }, "language": { "message": "Language" }, @@ -68,6 +80,9 @@ "ram": { "message": "RAM" }, + "reset": { + "message": "Reset" + }, "screen": { "message": "Screen" }, diff --git a/assets/data/user-agent.json b/assets/data/user-agent.json new file mode 100644 index 0000000..ab37a08 --- /dev/null +++ b/assets/data/user-agent.json @@ -0,0 +1,123 @@ +{ + "car": { + "Tesla": "Mozilla/5.0 (X11; GNU/Linux) AppleWebKit/537.36 (KHTML, like Gecko) Chromium/88.0.4324.150 Chrome/88.0.4324.150 Safari/537.36 Tesla/2021.4.18.2-6c676ce09ea5" + }, + "computer": { + "Windows": { + "Windows 10": { + "Chrome": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0 Safari/537.36", + "Firefox": "Mozilla/5.0 (Windows NT 10.0; rv:95.0) Gecko/20171102 Firefox/95.0", + "Opera": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 OPR/79.0.4143.61", + "Edge": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 Edg/94.0.992.31/PmaOHqHf-37", + "Vivaldi": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.83 Safari/537.36 Vivaldi/4.2.2406.48", + "Whale": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.232 Whale/2.10.124.26 Safari/537.36" + }, + "Windows 8.1": { + "Chrome": "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.8948.8989 Safari/537.36", + "Firefox": "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0/10csO9CgK-99", + "Opera": "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 OPR/79.0.4143.50 (Edition Yx 02)", + "Edge": "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 Edg/94.0.992.31", + "Vivaldi": "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.122 Safari/537.36 Vivaldi/2.3.1440.60", + "Whale": "Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.229 Whale/2.10.123.42 Safari/537.36" + }, + "Windows 8": { + "Chrome": "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.48 CitizenFX/1.0.0.4590 Safari/537.36", + "Firefox": "Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0/10csO9CgK-99", + "Opera": "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 OPR/79.0.4143.66", + "Edge": "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 Edg/94.0.992.31", + "Vivaldi": "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.143 Safari/537.36 Vivaldi/1.95.1077.45", + "Whale": "Mozilla/5.0 (Windows NT 6.2; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Whale/2.8.108.15 Safari/537.36" + }, + "Windows 7": { + "Chrome": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.48 CitizenFX/1.0.0.4590 Safari/537.36", + "Firefox": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0/CZyfq6zd2FAGsZdS0An", + "Opera": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 OPR/79.0.4143.66 (Edition Campaign 70)", + "Edge": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 Edg/94.0.992.31", + "Vivaldi": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.183 Safari/537.36 Vivaldi/6969562071AB", + "Whale": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.232 Whale/2.10.124.26 Safari/537.36", + "Internet Explorer": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.2)" + }, + "Windows Vista": { + "Chrome": "Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", + "Firefox": "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9.1b2pre) Gecko/20081026 Minefield/3.1b2pre", + "Opera": "Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 OPR/78.0.4093.231", + "Edge": "Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299", + "Vivaldi": "Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36 Vivaldi/1.0.435.46", + "Internet Explorer": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; BOIE9;FRFR)" + }, + "Windows XP": { + "Chrome": "Mozilla/5.0 (Windows XP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36", + "Firefox": "Mozilla/5.0 (Windows; U; Windows XP) Gecko MultiZilla/1.6.1.0a", + "Opera": "Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.99", + "Internet Explorer": "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" + }, + "Windows 2000": { + "Firefox": "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8) Gecko/20051111 Firefox/1.5", + "Opera": "Opera/9.80 (Windows NT 5.0; U; MRA 5.9 (build 4930); ru) Presto/2.10.229 Version/11.62", + "Internet Explorer": "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" + }, + "Windows 98": { + "Firefox": "Mozilla/5.0 (Windows; U; Win98; bg; rv:1.8.1.10) Gecko/20100526 Firefox/3.7a5pre", + "Opera": "Opera/8.20.(Windows 98; ro-RO) Presto/2.9.186 Version/11.00", + "Internet Explorer": "Mozilla/4.0 (compatible; MSIE 4.01; MSN 2.5; Windows 98)" + } + }, + "macOS": { + "Safari": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.7 Safari/605.1.15", + "Chrome": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4653.2 Safari/537.36", + "Firefox": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4; rv:87.0) Gecko/20100101 Firefox/87.0", + "Opera": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 OPR/79.0.4143.50", + "Edge": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 Edg/94.0.992.31", + "Vivaldi": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.88 Safari/537.36 Vivaldi/2.4.1488.36", + "Whale": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Whale/2.8.108.15 Safari/537.36" + }, + "Linux": { + "Chrome": "Mozilla/5.0 (Linux; 7.0; P2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36", + "Firefox": "Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.8) Gecko/20051111 Firefox/54.0", + "Vivaldi": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Vivaldi/4.1.2369.21" + } + }, + "gameConsole": { + "PlayStation": { + "PlayStation 4": "Mozilla/5.0 (PlayStation 4 5.05) AppleWebKit/601.2 (KHTML, like Gecko)", + "PlayStation 3": "Mozilla/5.0 (PLAYSTATION 3 4.81) AppleWebKit/531.22.8 (KHTML, like Gecko)", + "PlayStation Vita": "Mozilla/5.0 (PlayStation Vita 3.50) AppleWebKit/537.73 (KHTML, like Gecko) Silk/3.2", + "PlayStation Portable": "Mozilla/4.0 (PSP (PlayStation Portable); 2.00)" + }, + "Xbox": { + "Xbox One": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299", + "Xbox 360": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox)" + }, + "Nintendo": { + "Nintendo Switch": "Mozilla/5.0 (Nintendo Switch; WebApplet) AppleWebKit/606.4 (KHTML, like Gecko) NF/6.0.1.18.3 NintendoBrowser/5.1.0.21481", + "Nintendo Wii U": "Mozilla/5.0 (Nintendo WiiU) AppleWebKit/536.30 (KHTML, like Gecko) NX/3.0.4.2.13 NintendoBrowser/4.3.2.11274.US", + "Nintendo Wii": "Opera/9.30 (Nintendo Wii; U; ; 3642; en)", + "Nintendo 3DS": "Mozilla/5.0 (New Nintendo 3DS like iPhone) AppleWebKit/536.30 (KHTML, like Gecko) NX/3.0.0.5.22 Mobile NintendoBrowser/1.10.10166.US" + } + }, + "phone": { + "Android": { + "Chrome": "Mozilla/5.0 (Linux; Android 10; W-V680-OPE) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Mobile Safari/537.36", + "Firefox": "Mozilla/5.0 (Android 10.0; Mobile; rv:90.0) Gecko/90.0 Firefox/90.0", + "Opera": "Mozilla/5.0 (Linux; Android 11; CPH1979) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Mobile Safari/537.36 OPR/64.3.3282.60839", + "Edge": "Mozilla/5.0 (Linux; Android 11; Redmi Note 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Mobile Safari/537.36 EdgA/93.0.961.62" + }, + "iOS": { + "Safari": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.2 Mobile/15E148 Safari/604.1", + "Chrome": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/93.0.4577.78 Mobile/15E148 Safari/604.1", + "Firefox": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/37.0 Mobile/15E148 Safari/605.1.15" + }, + "Symbian": { + "Opera": "Opera/9.80 (S60; SymbOS; Opera Mobi/SYB-1204232254; U; en-GB) Presto/2.10.254 Version/12.00", + "Nokia Browser": "Nokia7610/2.0 (5.0509.0) SymbianOS/7.0s Series60/2.1 Profile/MIDP-2.0 Configuration/CLDC-1.0", + "Ovi 2.0": "Mozilla/5.0 (Series40; Nokia200/11.64; Profile/MIDP-2.1 Configuration/CLDC-1.1) Gecko/20100401 S40OviBrowser/2.0.2.68.14" + } + }, + "tv": { + "Google TV": "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/90.0.4430.212 Large Screen Safari/534.24 GoogleTV/092754youtube.com/tv#", + "Samsung TV": "Mozilla/5.0 (SMART-TV; Linux; Tizen 2.4.0) AppleWebkit/538.1 (KHTML, like Gecko) SamsungBrowser/1.1 TV Safari/538.1" + }, + "watch": { + "watchOS": "atc/1.0 watchOS/7.5 model/Watch3,3 hwp/t8004 build/18T567 (6; dt:155)" + } +} \ No newline at end of file diff --git a/assets/fonts/Poppins-Bold.ttf b/assets/fonts/Poppins-Bold.ttf deleted file mode 100644 index b94d47f..0000000 Binary files a/assets/fonts/Poppins-Bold.ttf and /dev/null differ diff --git a/assets/fonts/Poppins-Regular.ttf b/assets/fonts/Poppins-Regular.ttf deleted file mode 100644 index be06e7f..0000000 Binary files a/assets/fonts/Poppins-Regular.ttf and /dev/null differ diff --git a/assets/fonts/Poppins-SemiBold.ttf b/assets/fonts/Poppins-SemiBold.ttf deleted file mode 100644 index dabf7c2..0000000 Binary files a/assets/fonts/Poppins-SemiBold.ttf and /dev/null differ diff --git a/assets/fonts/Roboto-Bold.ttf b/assets/fonts/Roboto-Bold.ttf new file mode 100644 index 0000000..3742457 Binary files /dev/null and b/assets/fonts/Roboto-Bold.ttf differ diff --git a/assets/fonts/Roboto-Medium.ttf b/assets/fonts/Roboto-Medium.ttf new file mode 100644 index 0000000..e89b0b7 Binary files /dev/null and b/assets/fonts/Roboto-Medium.ttf differ diff --git a/assets/fonts/Roboto-Regular.ttf b/assets/fonts/Roboto-Regular.ttf new file mode 100644 index 0000000..3d6861b Binary files /dev/null and b/assets/fonts/Roboto-Regular.ttf differ diff --git a/assets/satus/satus.css b/assets/satus/satus.css new file mode 100644 index 0000000..dd1e3a1 --- /dev/null +++ b/assets/satus/satus.css @@ -0,0 +1,1858 @@ +/*-------------------------------------------------------------- +# SCROLLBAR +--------------------------------------------------------------*/ + +:where([class^='satus'])::-webkit-scrollbar { + width: 4px; +} + +:where([class^='satus'])::-webkit-scrollbar:hover { + width: 8px; +} + +:where([class^='satus'])::-webkit-scrollbar-thumb { + background: rgba(var(--satus-light), .2); +} + +:where([class^='satus'])::-webkit-scrollbar-thumb:hover { + background: rgba(var(--satus-light), .3); +} +/*-------------------------------------------------------------- +# ANIMATIONS +--------------------------------------------------------------*/ + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeInLeft { + from { + opacity: 0; + transform: translateX(-100%); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes fadeInRight { + from { + opacity: 0; + transform: translateX(100%); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +@keyframes fadeOutLeft { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(-50%); + } +} + +@keyframes fadeOutRight { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(50%); + } +} + +@keyframes zoomIn { + from { + transform: scale(.8); + opacity: 0; + } + to { + transform: scale(1); + opacity: 1; + } +} + +@keyframes zoomOut { + from { + transform: scale(1); + opacity: 1; + } + to { + transform: scale(.8); + opacity: 0; + } +} +/*-------------------------------------------------------------- +>>> THEMES +--------------------------------------------------------------*/ + +.satus-base { + --satus-light: 0, 20, 82; + --satus-primary: #ff4158; + + --satus-alert-hue-error: 0; + --satus-alert-hue-success: 200; + + --satus-base-background: #f3f4f6; + --satus-base-foreground: #565e76; + + --satus-checkbox-background: #f3f4f6; + --satus-checkbox-border: #dcdfe5; + --satus-checkbox-foreground: rgb(255, 255, 255, .96); + + --satus-divider: rgba(var(--satus-light),.1); + + --satus-header-background: #fff; + --satus-header-foreground: inherit; + --satus-header-shadow: 0 1px 0 #dcdee5; + + --satus-layers-background: var(--satus-base-background); + --satus-layers-foreground: inerit; + + --satus-section-background: #fff; + --satus-section-border: #dcdee5; + + --satus-sidebar-background: #fff; + --satus-sidebar-foreground: inherit; + --satus-sidebar-shadow: #dcdee5; + + --satus-modal-foreground: inherit; + --satus-modal-background: #fff; + --satus-modal-shadow: 0 1px 4px #7d86a1; + + --satus-tabs-background: var(--satus-section-background); + + --satus-text-field-background: #edf0f2; + --satus-text-field-border: #dcdee5; + --satus-text-field-color: #7d8ba1; + --satus-text-field-selection: rgb(149, 166, 178, .35); + --satus-text-field-cursor: #fa0; + + --satus-switch-track: #e1e4ea; + --satus-switch-track--checked: var(--satus-primary); + --satus-switch-thumb: #fff; +} +/*-------------------------------------------------------------- +>>> NORMALIZE +--------------------------------------------------------------*/ + +:where([class^='satus']) { + box-sizing: border-box; +} + +:where([class^='satus'])[hidden]:not([hidden='false']) { + display: none; +} + +:where([class^='satus'])[transparent] { + opacity: 0; +} +/*-------------------------------------------------------------- +>>> MODAL +---------------------------------------------------------------- +# Container +# Scrim +# Surface +# Variants + # Vertical menu +--------------------------------------------------------------*/ + + +/*-------------------------------------------------------------- +# CONTAINER +--------------------------------------------------------------*/ + +.satus-modal { + position: fixed; + z-index: 9; + top: 0; + left: 0; + display: flex; + width: 100vw; + height: 100vh; + justify-content: center; + align-items: center; +} + + +/*-------------------------------------------------------------- +# SCRIM +--------------------------------------------------------------*/ + +.satus-modal__scrim { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + animation: fadeIn 150ms linear forwards; + opacity: 0; + background: rgba(0, 0, 0, .16); + backdrop-filter: blur(8px); +} + +.satus-modal--closing .satus-modal__scrim { + animation: fadeOut 70ms linear forwards; +} + + +/*-------------------------------------------------------------- +# SURFACE +--------------------------------------------------------------*/ + +.satus-modal__surface { + display: flex; + overflow-y: auto; + flex-direction: column; + box-sizing: border-box; + width: 95%; + min-width: 240px; + max-width: 560px; + max-height: 80%; + margin: 8px; + padding: 12px 16px; + transform: scale(.8); + animation: zoomIn 150ms linear forwards; + animation-delay: 20ms; + opacity: 0; + color: var(--satus-modal-foreground); + border-radius: 3px; + background-color: var(--satus-modal-background); + box-shadow: var(--satus-modal-shadow); +} + +.satus-modal--closing .satus-modal__surface { + animation: zoomOut 70ms linear forwards; +} + +.satus-section--actions { + justify-content: flex-end; +} +.satus-section--actions > *:not(:first-child) { + margin-left: 8px; +} + + +/*-------------------------------------------------------------- +# VARIANTS +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# VERTICAL MENU +--------------------------------------------------------------*/ + +.satus-modal--vertical-menu .satus-modal__surface { + position: absolute; + top: 8px; + right: 8px; + left: auto; + min-width: 180px; + max-width: 180px; + margin: 0; + padding: 8px 0; + transform-origin: right top; +} + +.satus-modal--vertical-menu .satus-modal__surface>[class^='satus']:where(:not(.satus-divider)) { + height: 36px; + padding: 0 16px; + border-radius: 0; +} + +.satus-modal--vertical-menu .satus-modal__surface>.satus-span { + font-size: 13px; + font-weight: 500; + margin: 6px 0; + padding: 0 12px; +} + +.satus-modal--vertical-menu .satus-modal__surface>.satus-tabs { + margin: 0 12px; + border-radius: 3px; + height: 26px; + padding: 0; +} + +.satus-modal--vertical-menu .satus-select svg, +.satus-modal--vertical-menu .satus-button svg { + margin: 0 14px 0 0; + opacity: .64; + flex: 0 0 18px; +} + +.satus-modal--vertical-menu .satus-button .satus-span { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +/*-------------------------------------------------------------- +>>> GRID +--------------------------------------------------------------*/ + +.satus-grid { + display: flex; + align-items: stretch; + height: 100%; + padding: 8px; +} +/*-------------------------------------------------------------- +>>> TEXT FIELD +---------------------------------------------------------------- +# Parts + # Container + # Input + # +# Syntax highlighting + # Regular expression +--------------------------------------------------------------*/ + +.satus-text-field { + display: flex; + + min-width: 240px; + height: 36px; + + color: var(--satus-text-field-foreground, inherit); + border-radius: 4px; + background: var(--satus-text-field-background); + + align-items: center; + justify-content: space-between; +} + +.satus-text-field__container { + position: relative; + + overflow: hidden; + + height: 100%; + + flex: 1; +} + +.satus-text-field__textarea { + font: inherit; + + position: absolute; + z-index: 9; + top: 0; + left: 0; + + overflow: auto; + + width: 100%; + min-width: 0; + max-width: none; + height: 100%; + min-height: 0; + max-height: none; + margin: 0; + padding: 0 12px; + + white-space: pre; + + opacity: 0; + color: inherit; + border: none; + border-radius: 4px; + outline: none; + + appearance: none; + overflow-wrap: normal; +} + +.satus-text-field__display { + position: absolute; + top: 0; + left: 0; + + display: flex; + + width: 100%; + height: 100%; +} + +.satus-text-field__line-numbers { + padding: 0 12px 0 0; + + opacity: .5; +} + +.satus-text-field__line-numbers>span { + font-size: inherit; + + display: block; + + width: 100%; + + text-align: right; +} + +.satus-text-field__pre { + font: inherit; + + display: flex; + + margin: 0; +} + +.satus-text-field__hidden-value { + font: inherit; + + position: absolute; + + overflow: auto; + + white-space: pre; + pointer-events: none; + + opacity: 0; + + overflow-wrap: normal; +} + +.satus-text-field__selection { + position: absolute; + top: 0; + left: 0; + + display: none; + + width: 0; + height: 22px; + margin: 6px 12px; + + border: 1px solid var(--satus-text-field-selection); + border-radius: 3px; + background: var(--satus-text-field-selection); +} + +.satus-text-field__cursor { + position: absolute; + top: 0; + left: 0; + + display: none; + + width: 2px; + height: 22px; + margin: -3px 0 0; + + animation: blink 1s step-end 8; + + background: var(--satus-text-field-cursor); +} + +.satus-text-field__textarea:focus+.satus-text-field__display>.satus-text-field__cursor, +.satus-text-field__textarea:focus+.satus-text-field__display>.satus-text-field__selection:not([disabled]) { + display: block; +} + +@keyframes blink { + + from, + to { + opacity: 1; + } + + 50% { + opacity: 0; + } +} + + +/*-------------------------------------------------------------- +# SYNTAX HIGHLIGHTING +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# REGULAR EXPRESSION +--------------------------------------------------------------*/ + +.satus-text-field__pre>.group { + color: #47ff47; + background-color: rgb(71, 255, 71, .16); +} + +.satus-text-field__pre>.character-class { + color: #ffc247; + background-color: rgb(255, 170, 0, .16); +} + +.satus-text-field__pre>.quantifier { + color: #47c2ff; + background-color: rgb(71, 194, 255, .16); +} + +.satus-text-field__pre>.anchor { + color: #47c2ff; + background-color: rgb(71, 194, 255, .16); +} + +.satus-text-field__pre>.metasequence { + color: #47ff47; + background-color: rgb(71, 255, 71, .16); +} + +.satus-text-field__pre>.text { + color: #c4c4d4; + background-color: rgb(196, 196, 212, .16); +} +/*-------------------------------------------------------------- +>>> CHART +--------------------------------------------------------------*/ + +.satus-chart { + font-size: 90%; + + position: relative; + + height: 128px; + margin: 4px 12px; + + color: rgba(var(--satus-light), .32); + border: 1px dashed rgba(var(--satus-light), .2); + border-top: unset; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} + +.satus-chart__labels { + position: absolute; + top: 0; + left: 0; + + display: flex; + + width: 100%; + height: 100%; + + justify-content: space-between; + align-items: stretch; +} + +.satus-chart__section { + padding: 4px; + + flex: 1; +} + +.satus-chart__section:not(:last-child) { + border-right: 1px dashed rgba(var(--satus-light), .2); +} + + +.satus-chart__bars { + position: absolute; + top: 0; + left: 0; + + display: flex; + + width: 100%; + height: 100%; + + justify-content: space-between; + align-items: stretch; +} + +.satus-chart__bar { + display: flex; + flex-direction: column; + + margin: 0 1px; + + flex: 1; + align-items: center; + justify-content: flex-end; +} + +.satus-chart__piece { + width: 100%; +} + +.satus-chart__piece:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} +/*-------------------------------------------------------------- +>>> SELECT +--------------------------------------------------------------*/ + +.satus-select { + position: relative; + + display: flex; + + cursor: pointer; + + align-items: center; + justify-content: space-between; +} + +.satus-select:hover { + background-color: var(--satus-hover); +} + +.satus-select__content { + display: flex; + + flex: 2; + overflow: hidden; + + align-items: center; +} + +.satus-select svg { + width: 20px; + height: 18px; + margin: 0 14px 0 0; + + opacity: .64; +} + +.satus-select__content .satus-span { + overflow: hidden; + + text-overflow: ellipsis; +} + +.satus-select__value { + display: block; + overflow: hidden; + + flex: 1; + margin-left: 8px; + + text-align: right; + text-overflow: ellipsis; + + opacity: .64; +} + +.satus-select select { + font: inherit; + + position: absolute; + z-index: 1; + top: 0; + left: 0; + + width: 100%; + height: 100%; + margin: 0; + padding: inherit; + + cursor: inherit; + + opacity: 0; + border: none; + outline: none; + + appearance: none; +} + +.satus-select:hover { + cursor: pointer; + + background-color: rgba(var(--satus-light), .06); +} + +.satus-select:focus { + background-color: rgba(var(--satus-light), .08); +} + +.satus-select select::-webkit-scrollbar { + width: 4px; +} + +.satus-select select::-webkit-scrollbar:hover { + width: 8px; +} + +.satus-select select::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, .2); +} + +.satus-select select::-webkit-scrollbar-thumb:hover { + background: rgba(0, 0, 0, .3); +} + +.satus-select option { + color: var(--satus-select-text); + background: var(--satus-select-background); +} +/*-------------------------------------------------------------- +>>> DIVIDER +--------------------------------------------------------------*/ + +.satus-divider { + height: 1px; + margin: 16px 0 12px; + background: var(--satus-divider); +} +/*-------------------------------------------------------------- +>>> SECTION +---------------------------------------------------------------- +# Variants + # Align start + # Align end + # Card +# Media +--------------------------------------------------------------*/ + +.satus-section { + display: flex; + + flex-wrap: wrap; +} + + +/*-------------------------------------------------------------- +# ALIGN START +--------------------------------------------------------------*/ + +.satus-section--align-start { + align-items: center; +} + +.satus-section--align-start>*:not(:last-child) { + margin-right: 8px; +} + + +/*-------------------------------------------------------------- +# ALIGN END +--------------------------------------------------------------*/ + +.satus-section--align-end { + align-items: center; + justify-content: flex-end; +} + +.satus-section--align-end>*:not(:first-child) { + margin-left: 8px; +} + + +/*-------------------------------------------------------------- +# CARD +--------------------------------------------------------------*/ + +.satus-section--card { + flex-direction: column; + + max-width: 900px; + margin: 12px; + padding: 8px 0; + + border: 1px solid var(--satus-section-border); + border-radius: 3px; + background: var(--satus-section-background); +} + +.satus-section--transparent-card { + max-width: 900px; + margin: 8px 12px; +} + +.satus-section--card[data-title], +.satus-section--transparent-card[data-title] +{ + position: relative; + + margin-top: 32px; +} + +.satus-section--card[data-title]::before, +.satus-section--transparent-card::before +{ + position: absolute; + top: -8px; + left: 0; + + content: attr(data-title); + transform: translateY(-100%); +} + + +.satus-section--transparent-card > [class^='satus'] { + width: 100%; +} + +.satus-section--card>[class^='satus']:not(.satus-list):not(.satus-section) { + display: flex; + + width: 100%; + min-height: 48px; + padding: 8px 12px; + + transition: background-color .18s cubic-bezier(.25, .8, .5, 1); + text-align: left; + + border-radius: 0; + + align-items: center; +} + +.satus-section--card>[class^='satus']:not(.satus-list):hover { + background-color: rgba(var(--satus-light), .06); +} + +.satus-section--card>.satus-button { + justify-content: flex-start; +} + +.satus-section--card>.satus-button>svg, +.satus-section--card>.satus-select>svg +{ + width: 20px; + margin: 0 14px 0 0; + + color: var(--satus-primary); +} + +.satus-section--card>.satus-span { + display: flex; + + align-items: center; +} + +.satus-section--transparent { + background: unset; + border: unset; + padding: 0; + border-radius: unset; +} + + +/*-------------------------------------------------------------- +# MEDIA +--------------------------------------------------------------*/ + +@media (min-width: 901px) { + .satus-section--card, + .satus-section--transparent-card { + margin-left: auto; + margin-right: auto; + } +} +/*-------------------------------------------------------------- +>>> BASE +--------------------------------------------------------------*/ + +.satus-base { + display: flex; + flex-direction: column; + + width: 100%; + height: 100%; + + color: var(--satus-base-foreground); + background: var(--satus-base-background); +} +/*-------------------------------------------------------------- +>>> ALERT +---------------------------------------------------------------- +# Media +--------------------------------------------------------------*/ + +.satus-alert { + display: flex; + min-height: 48px; + margin: 12px; + padding: 8px 12px; + border-radius: 3px; + align-items: center; + max-width: 900px; +} + +.satus-alert--error { + color: hsl(var(--satus-alert-hue-error), 56%, 64%); + border: 1px solid hsl(var(--satus-alert-hue-error), 56%, 28%); + background: hsl(var(--satus-alert-hue-error), 56%, 20%); +} + +.satus-alert--success { + color: hsl(var(--satus-alert-hue-success), 56%, 56%); + border: 1px solid hsl(var(--satus-alert-hue-success), 56%, 26%); + background: hsl(var(--satus-alert-hue-success), 56%, 18%); +} + + +/*-------------------------------------------------------------- +# MEDIA +--------------------------------------------------------------*/ + +@media (min-width: 901px) { + .satus-alert { + margin-left: auto; + margin-right: auto; + } +} +/*-------------------------------------------------------------- +>>> MAIN +--------------------------------------------------------------*/ + +.satus-main { + display: flex; + background: var(--satus-base-background); + flex: 1 +} +/*-------------------------------------------------------------- +>>> SIDEBAR +--------------------------------------------------------------*/ + +.satus-sidebar { + z-index: 1; + display: flex; + flex-direction: column; + width: 56px; + padding: 12px 0; + color: var(--satus-sidebar-foreground); + background: var(--satus-sidebar-background); + box-shadow: 1px 0 0 var(--satus-sidebar-shadow) +} +/*-------------------------------------------------------------- +>>> LAYERS +--------------------------------------------------------------*/ + +.satus-layers { + position: relative; + + overflow: hidden; + + flex: 1; +} + +.satus-layers__layer { + position: absolute; + top: 0; + left: 0; + + overflow: auto; + + width: 100%; + height: 100%; + + color: var(--satus-layers-foreground); + background: var(--satus-layers-background); +} +/*-------------------------------------------------------------- +>>> LIST +--------------------------------------------------------------*/ + +.satus-list { + margin: 0; + + list-style: none; +} + +.satus-list__item { + display: flex; + + min-height: 48px; + padding: 0 16px; + + align-items: center; + justify-content: space-between; +} + +.satus-list__item>*:not(:first-child) { + margin-left: 8px; +} + +.satus-list__item>*:last-child { + font-size: 92%; + + text-align: right; + + opacity: .64; +} +/*-------------------------------------------------------------- +>>> COLOR PICKER: +---------------------------------------------------------------- +# Button +# Modal +--------------------------------------------------------------*/ + + +/*-------------------------------------------------------------- +# BUTTON +--------------------------------------------------------------*/ + +.satus-color-picker { + font-size: inherit; + + position: relative; + + display: flex; + + box-sizing: border-box; + margin: 0; + + cursor: pointer; + + color: inherit; + border: none; + outline: none; + background-color: var(--satus-theme-button); + + justify-content: space-between; + -webkit-tap-highlight-color: transparent; + align-items: center; + -webkit-appearance: none; +} + +.satus-color-picker__value { + width: 22px; + height: 22px; + + border: 2px solid rgba(0, 0, 0, .16); + border-radius: 50%; +} + + +/*-------------------------------------------------------------- +# MODAL +--------------------------------------------------------------*/ + +.satus-modal--color-picker .satus-modal__surface { + padding: 8px; +} + +.satus-color-picker__palette { + position: relative; + + overflow: hidden; + + width: 100%; + height: 256px; + margin: 0 0 4px; + + border-radius: 5px; + background-color: #f00; +} + +.satus-color-picker__palette:before { + position: absolute; + top: 0; + left: 0; + + width: 100%; + height: 100%; + + content: ''; + + background-image: linear-gradient(0deg, black, transparent), linear-gradient(90deg, white, transparent); +} + +.satus-color-picker__cursor { + position: absolute; + + width: 5px; + height: 5px; + + transform: translate(-50%, -50%); + pointer-events: none; + + border: 1px solid #fff; + border-radius: 50%; + box-shadow: 0 0 0 1px #000; +} + +.satus-modal--color-picker .satus-modal__surface .satus-section--color { + margin: 8px 4px; + + align-items: center; +} + +.satus-color-picker__color { + width: 32px; + height: 32px; + margin: 0 16px 0 0; + + border: 2px solid rgba(0, 0, 0, .16); + border-radius: 50%; + background: #f00; +} + +.satus-slider.satus-color-picker__hue { + padding: 0; + + flex: 1; +} + +.satus-color-picker__hue .satus-slider__track-container { + height: 16px; + margin: 0; + + border-radius: 4px; + background-image: linear-gradient(90deg, #f00, #ff2a00, #f50, #ff7f00, #fa0, #ffd400, #ff0, #d4ff00, #af0, #80ff00, #5f0, #2bff00, #0f0, #00ff2b, #0f5, #00ff80, #0fa, #00ffd5, #0ff, #00d4ff, #0af, #007fff, #05f, #002bff, #00f, #2a00ff, #50f, #7f00ff, #a0f, #d400ff, #f0f, #ff00d4, #f0a, #ff0080, #f05, #ff002b, #f00); +} + +.satus-color-picker__hue .satus-slider__track-container::before { + display: none; +} + +.satus-color-picker__hue .satus-slider__track { + background: transparent; +} + +.satus-color-picker__hue .satus-slider__track::after { + width: 16px; + height: 16px; + + background: #fff; + box-shadow: 0 0 4px rgb(0, 0, 0, .64); +} +/*-------------------------------------------------------------- +>>> SPAN +--------------------------------------------------------------*/ + +.satus-span--title { + font-weight: 500; + overflow: hidden; + + white-space: nowrap; + text-overflow: ellipsis; + + flex: 1; +} +/*-------------------------------------------------------------- +>>> BUTTON +---------------------------------------------------------------- +# Base +# Basic +# Icon +--------------------------------------------------------------*/ + + +/*-------------------------------------------------------------- +# BASE +--------------------------------------------------------------*/ + +.satus-button { + font: inherit; + + position: relative; + + display: inline-flex; + overflow: hidden; + + height: 36px; + padding: 8px; + + transition: background-color .3s cubic-bezier(.25, .8, .5, 1); + + color: inherit; + border: none; + border-radius: 6px; + outline: none; + background: transparent; + + appearance: none; + align-items: center; +} + +.satus-button:hover { + cursor: pointer; + + background-color: rgba(var(--satus-light), .06); +} + +.satus-button:focus { + background-color: rgba(var(--satus-light), .08); +} + +.satus-button svg { + width: 100%; + max-width: 24px; + height: 100%; + max-height: 24px; +} + + +/*-------------------------------------------------------------- +# BASIC +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# ICON +--------------------------------------------------------------*/ + +.satus-button--icon { + width: 40px; + height: 40px; + + border-radius: 50%; +} + +.satus-button--icon svg { + width: 24px; + height: 24px; +} +/*-------------------------------------------------------------- +>>> HEADER +--------------------------------------------------------------*/ + +.satus-header { + z-index: 1; + + display: flex; + + height: 56px; + padding: 0 12px; + + color: var(--satus-header-foreground); + background: var(--satus-header-background); + box-shadow: var(--satus-header-shadow); + + justify-content: space-between; + align-items: center; +} +/*-------------------------------------------------------------- +>>> RADIO +--------------------------------------------------------------*/ + +.satus-radio { + position: relative; + display: flex; +} + +.satus-radio__input { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + opacity: 0; + margin: 0; + z-index: 9; +} + +.satus-radio__content { + flex: 1; + padding: 0 12px; +} + +.satus-radio__i { + width: 16px; + height: 16px; + border: 1px solid rgba(var(--satus-light),.64); + border-radius: 50%; + transition: 200ms; +} + +.satus-radio__input + .satus-radio__i::before { + width: 8px; + height: 8px; + margin: 3px; + border-radius: 50%; + background: var(--satus-primary); + content: ''; + display: block; + transform: scale(0); + transition: 200ms; +} + +.satus-radio__input:checked + .satus-radio__i { + border-color: var(--satus-primary); +} + +.satus-radio__input:checked + .satus-radio__i::before { + background: var(--satus-primary); + transform: scale(1); +} +/*-------------------------------------------------------------- +>>> SLIDER +--------------------------------------------------------------*/ + +.satus-slider { + display: flex; + + flex-wrap: wrap; +} + +.satus-slider__track-container { + position: relative; + + width: 100%; + height: 20px; + margin: 10px 0 -2px; +} + +.satus-slider__track-container::before { + position: absolute; + top: calc(50% - 1px); + left: 0; + + width: 100%; + height: 2px; + + content: ''; + + opacity: .24; + background: var(--satus-primary); +} + +.satus-slider__input { + position: absolute; + top: 0; + left: 0; + + width: 100%; + height: 100%; + margin: 0; + + opacity: 0; +} + +.satus-slider__track { + position: absolute; + top: calc(50% - 1px); + left: 0; + + width: 0; + height: 2px; + + background: var(--satus-primary); + pointer-events: none; +} + +.satus-slider__track::before { + position: absolute; + top: 50%; + right: 0; + transform: translate(50%, -50%); + display: block; + width: 16px; + height: 16px; + content: ''; + transition: width 200ms, height 200ms, opacity 200ms; + opacity: 0; + border-radius: 50%; + background: var(--satus-primary); +} + +.satus-slider__input:focus + .satus-slider__track::before { + width: 24px; + height: 24px; + opacity: .16; +} + +.satus-slider__input:active + .satus-slider__track::before { + width: 26px; + height: 26px; + opacity: .16; +} + +.satus-slider__track::after { + position: absolute; + top: 50%; + right: 0; + transform: translate(50%, -50%); + + width: 10px; + height: 10px; + + content: ''; + + border-radius: 50%; + background: var(--satus-primary); + pointer-events: none; + transition: width 200ms, height 200ms, opacity 200ms; +} + +.satus-slider__input:active + .satus-slider__track::after +{ + width: 12px; + height: 12px; +} + + + + + +.satus-slider--row { + flex-wrap: nowrap; + justify-content: space-between; +} + +.satus-slider--row .satus-slider__track-container { + margin: 0 0 -2px 12px; + max-width: 50%; +} +/*-------------------------------------------------------------- +>>> TABS +--------------------------------------------------------------*/ + +.satus-tabs { + position: relative; + + display: flex; + + border: 2px solid var(--satus-tabs-background); + border-radius: 4px; + background: var(--satus-tabs-background); +} + +.satus-tabs::before { + position: absolute; + top: 0; + left: calc(calc(100% / var(--satus-tabs-count)) * var(--satus-tabs-current)); + + width: calc(100% / var(--satus-tabs-count)); + height: 100%; + + content: ''; + transition: left .25s; + + border-radius: 3px; + background: var(--satus-tabs-foreground); +} + +.satus-tabs__button { + font: inherit; + + position: relative; + z-index: 1; + + overflow: hidden; + + margin: 0; + padding: 0 8px; + + text-transform: lowercase; + text-overflow: ellipsis; + + color: inherit; + border: none; + border-radius: 3px; + outline: none; + background: transparent; + + flex: 1; + appearance: none; +} +/*-------------------------------------------------------------- +>>> SHORTCUT: +---------------------------------------------------------------- +# +--------------------------------------------------------------*/ + +.satus-shortcut__value { + font-size: 11px; + + display: flex; + + margin-left: 16px; + + text-transform: uppercase; + + align-items: center; + flex: 1; + justify-content: flex-end; +} + +.satus-shortcut__actions { + display: flex; + + justify-content: flex-end; +} + +.satus-shortcut__actions .satus-button { + height: 32px; + margin: 8px 4px 0; + + border-radius: 8px; + background: rgba(0, 0, 0, .15); +} + +.satus-shortcut__actions .satus-button:hover { + background: rgba(0, 0, 0, .25); +} + +.satus-shortcut__primary { + display: flex; + + height: 64px; + margin: 0 0 12px; + padding: 16px; + + border-radius: 3px; + background: rgba(0, 0, 0, .16); + + align-items: center; +} + +.satus-shortcut__key { + display: flex; + + min-width: 32px; + height: 32px; + padding: 4px 8px; + + color: #242424; + border-radius: 4px; + background: #fff; + box-shadow: 0 1px 3px rgba(0, 0, 0, .15), inset 0 -3px 0 rgba(0, 0, 0, .1); + + align-items: center; + justify-content: center; +} + +.satus-shortcut__value>.satus-shortcut__key { + font-size: 14px; + + min-width: 24px; + height: 24px; +} + +.satus-shortcut__plus { + position: relative; + + width: 12px; + height: 12px; + margin: 8px; +} + +.satus-shortcut__plus::before { + position: absolute; + top: 0; + left: 5px; + + width: 2px; + height: 12px; + + content: ''; + + background-color: #aaa; +} + +.satus-shortcut__plus::after { + position: absolute; + top: 5px; + left: 0; + + width: 12px; + height: 2px; + + content: ''; + + background-color: #aaa; +} + +.satus-shortcut__mouse { + position: relative; + + display: flex; + + width: 28px; + height: 36px; + + border-radius: 50%; + border-top-left-radius: 12px; + border-top-right-radius: 12px; + background: #fff; + box-shadow: 0 1px 3px rgba(0, 0, 0, .15), inset 0 -3px 0 rgba(0, 0, 0, .1); +} + +.satus-shortcut__value>.satus-shortcut__mouse { + width: 22px; + height: 28px; +} + +.satus-shortcut__mouse>div { + position: absolute; + top: 0; + left: calc(50% - 1px); + + width: 2px; + height: 11px; + + border-radius: 2px; + background: #ccc; +} + +.satus-shortcut__mouse::before { + position: absolute; + top: -16%; + right: 14%; + + width: 2px; + height: 60%; + + content: ''; + + background: #f96754; +} + +.satus-shortcut__mouse.false::before { + top: -6%; +} + +.satus-shortcut__mouse.false::after { + position: absolute; + top: -20%; + right: calc(14% - 4px); + + width: 0; + height: 0; + + content: ''; + + border-right: 5px solid transparent; + border-bottom: 8px solid #f96754; + border-left: 5px solid transparent; +} + +.satus-shortcut__mouse.true::after { + position: absolute; + top: 40%; + right: calc(14% - 4px); + + width: 0; + height: 0; + + content: ''; + + border-top: 8px solid #f96754; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} + +.satus-shortcut__mouse.click::before { + position: absolute; + top: 0; + left: -1px; + + width: 10px; + height: 10px; + + content: ''; + + border-radius: 50%; + background: #f96754; +} + +.satus-shortcut__mouse.middle::before { + position: absolute; + z-index: 1; + top: 0; + left: 50%; + + width: 10px; + height: 10px; + + content: ''; + transform: translateX(-50%); + + border-radius: 50%; + background: #f96754; +} + +.satus-shortcut__mouse.context::before { + position: absolute; + top: 0; + left: 15px; + + width: 10px; + height: 10px; + + content: ''; + + border-radius: 50%; + background: #f96754; +} + +.satus-section_shortcut { + width: 100%; + margin: 8px 0 0; + + justify-content: flex-end; +} + +.satus-button_shortcut { + font-weight: 500; + + overflow: hidden; + + height: 28px; + min-height: 28px; + margin-right: 2px; + padding: 4px 8px; + + text-transform: uppercase; + + color: #f96754; + border-radius: 4px; +} +/*-------------------------------------------------------------- +>>> CHECKBOX +--------------------------------------------------------------*/ + +.satus-checkbox +{ + display: flex; + align-items: center; + position: relative; + cursor: pointer; +} + +.satus-checkbox::before +{ + display: flex; + width: 16px; + min-width: 16px; + height: 16px; + margin: 0 14px 0 0; + content: ''; + border: 1px solid var(--satus-checkbox-border); + border-radius: 3px; + background: var(--satus-checkbox-background); + align-items: center; + justify-content: center; +} + +.satus-checkbox[data-value=true]::before +{ + background: var(--satus-primary); + border-color: var(--satus-primary); +} + +.satus-checkbox[data-value=true]::after +{ + position: absolute; + top: 20px; + left: 20px; + + width: 8px; + height: 4px; + + content: ''; + transform: rotate(-45deg); + + border: 2px solid var(--satus-checkbox-foreground); + border-top: none; + border-right: none; +} + +/*-------------------------------------------------------------- +>>> SWITCH +---------------------------------------------------------------- +# Container +# Track +# Thumb +--------------------------------------------------------------*/ + + +/*-------------------------------------------------------------- +# CONTAINER +--------------------------------------------------------------*/ + +.satus-switch { + font: inherit; + + display: flex; + + transition: background-color 75ms; + + color: inherit; + border: none; + outline: none; + background-color: transparent; + + justify-content: space-between; + align-items: center; +} + +.satus-switch:hover { + cursor: pointer; +} + +.satus-switch__content { + display: flex; + + align-items: center; +} + +.satus-switch__content>svg { + width: 20px; + height: 18px; + margin: 0 14px 0 0; + + opacity: .64; +} + + +/*-------------------------------------------------------------- +# TRACK +--------------------------------------------------------------*/ + +.satus-switch>i { + width: 32px; + height: 18px; + + transition: background-color 150ms; + + border-radius: 18px; + background-color: var(--satus-switch-track); + + flex: 0 0 32px; +} + +.satus-section--card .satus-switch>i { + margin-left: 16px; +} + +.satus-switch[data-value='true']>i { + background-color: var(--satus-switch-track--checked); +} + + +/*-------------------------------------------------------------- +# THUMB +--------------------------------------------------------------*/ + +.satus-switch>i::before { + display: block; + + width: 14px; + height: 14px; + margin: 2px; + + content: ''; + transition: transform 150ms cubic-bezier(.4, 0, .2, 1); + + border-radius: 50%; + background-color: var(--satus-switch-thumb); + + will-change: transform; +} + +.satus-switch[data-value='true']>i::before { + transform: translateX(14px); +} diff --git a/assets/satus/satus.js b/assets/satus/satus.js new file mode 100644 index 0000000..6ce2104 --- /dev/null +++ b/assets/satus/satus.js @@ -0,0 +1,2979 @@ +/*-------------------------------------------------------------- +>>> CORE +---------------------------------------------------------------- +# Global variable +# Animations duration +# Append +# Attr +# Camelize +# Class +# Create element +# CSS +# Empty +# Element index +# Events +# Get property +# Is +# On +# Render +# Sort +# Storage + # Clear + # Get + # Import + # Set + # Remove + # On changed +# Localization +# Log +# Text +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# GLOBAL VARIABLE +--------------------------------------------------------------*/ + +var satus = { + components: {}, + events: { + data: {} + }, + locale: { + data: {} + }, + storage: { + data: {}, + type: 'extension' + } +}; + + +/*-------------------------------------------------------------- +# ANIMATION DURATION +--------------------------------------------------------------*/ + +satus.getAnimationDuration = function (element) { + return Number(window.getComputedStyle(element).getPropertyValue('animation-duration').replace(/[^0-9.]/g, '')) * 1000; +}; + + +/*-------------------------------------------------------------- +# APPEND +--------------------------------------------------------------*/ + +satus.append = function (child, parent) { + (parent || document.body).appendChild(child); +}; + + +/*-------------------------------------------------------------- +# ATTR +--------------------------------------------------------------*/ + +satus.attr = function (element, attributes) { + if (attributes) { + for (var name in attributes) { + var value = attributes[name]; + + if (satus.isFunction(value)) { + value = value(); + } + + if (element.namespaceURI) { + if (value === false) { + element.removeAttributeNS(null, name); + } else { + element.setAttributeNS(null, name, value); + } + } else { + if (value === false) { + element.removeAttribute(name); + } else { + element.setAttribute(name, value); + } + } + } + } +}; + + +/*-------------------------------------------------------------- +# CAMELIZE +--------------------------------------------------------------*/ + +satus.camelize = function (string) { + var result = ''; + + for (var i = 0, l = string.length; i < l; i++) { + var character = string[i]; + + if (character === '_' || character === '-') { + i++; + + result += string[i].toUpperCase(); + } else { + result += character; + } + } + + return result; +}; + + +/*-------------------------------------------------------------- +# CLASS +--------------------------------------------------------------*/ + +satus.class = function (element, className) { + if (className) { + element.classList.add(className); + } +}; + + +/*-------------------------------------------------------------- +# CREATE ELEMENT +--------------------------------------------------------------*/ + +satus.createElement = function (tagName, componentName, namespaceURI) { + var camelizedTagName = this.camelize(tagName), + className = 'satus-' + (componentName || tagName), + element, + match = className.match(/__[^__]+/g); + + if (!namespaceURI) { + if (tagName === 'svg') { + namespaceURI = 'http://www.w3.org/2000/svg'; + } + } + + if (namespaceURI) { + element = document.createElementNS(namespaceURI, tagName); + } else if (this.components[camelizedTagName]) { + element = document.createElement('div'); + } else { + element = document.createElement(tagName); + } + + if (match && match.length > 1) { + className = className.slice(0, className.indexOf('__')) + match[match.length - 1]; + } + + element.componentName = componentName; + element.className = className; + + element.createChildElement = function (tagName, componentName, namespaceURI) { + var element = satus.createElement(tagName, this.componentName + '__' + (componentName || tagName), namespaceURI); + + this.appendChild(element); + + return element; + }; + + return element; +}; + + +/*-------------------------------------------------------------- +# CSS +--------------------------------------------------------------*/ + +satus.css = function (element, property) { + return window.getComputedStyle(element).getPropertyValue(property); +}; + + +/*-------------------------------------------------------------- +# DATA +--------------------------------------------------------------*/ + +satus.data = function (element, data) { + if (data) { + for (var key in data) { + var value = data[key]; + + if (satus.isFunction(value)) { + value = value(); + } + + element.dataset[key] = value; + } + } +}; + + +/*-------------------------------------------------------------- +# EMPTY +--------------------------------------------------------------*/ + +satus.empty = function (element, exclude = []) { + for (var i = element.childNodes.length - 1; i > -1; i--) { + var child = element.childNodes[i]; + + if (exclude.indexOf(child) === -1) { + child.remove(); + } + } +}; + + +/*-------------------------------------------------------------- +# ELEMENT INDEX +--------------------------------------------------------------*/ + +satus.elementIndex = function (element) { + return Array.prototype.slice.call(element.parentNode.children).indexOf(element); +}; + + +/*-------------------------------------------------------------- +# EVENTS +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# ON +--------------------------------------------------------------*/ + +satus.events.on = function (type, handler) { + if (!this.data[type]) { + this.data[type] = []; + } + + this.data[type].push(handler); +}; + + +/*-------------------------------------------------------------- +# TRIGGER +--------------------------------------------------------------*/ + +satus.events.trigger = function (type) { + var handlers = this.data[type]; + + if (handlers) { + for (var i = 0, l = handlers.length; i < l; i++) { + handlers[i](); + } + } +}; + + +/*-------------------------------------------------------------- +# FETCH +--------------------------------------------------------------*/ + +satus.fetch = function (url, success, error, type) { + fetch(url).then(function (response) { + if (response.ok) { + response[type || 'json']().then(success); + } else { + error(); + } + }).catch(function () { + error(success); + }); +}; + + +/*-------------------------------------------------------------- +# GET PROPERTY +--------------------------------------------------------------*/ + +satus.getProperty = function (object, string) { + var properties = string.split('.'); + + for (var i = 0, l = properties.length; i < l; i++) { + var property = properties[i]; + + console.log(object); + + if (object = object[property]) { + if (i === l - 1) { + return object; + } + } else { + return false; + } + } +}; + + +/*-------------------------------------------------------------- +# ISSET +--------------------------------------------------------------*/ + +satus.isset = function (target, is_object) { + if (is_object === true) { + var keys = target.split('.').filter(function (value) { + return value != ''; + }); + + for (var i = 0, l = keys.length; i < l; i++) { + if (satus.isset(target[keys[i]])) { + target = target[keys[i]]; + } else { + return undefined; + } + } + + return target; + } else { + if (target === null || target === undefined) { + return false; + } + } + + return true; +}; + + +/*-------------------------------------------------------------- +# IS +--------------------------------------------------------------*/ + +satus.isArray = function (target) { + if (Array.isArray(target)) { + return true; + } else { + return false; + } +}; + +satus.isBoolean = function (target) { + return target === false || target === true; +}; + +satus.isElement = function (target) { + return target instanceof Element || target instanceof HTMLDocument; +}; + +satus.isFunction = function (target) { + return typeof target === 'function'; +}; + +satus.isNodeList = function (target) { + return target instanceof NodeList; +}; + +satus.isNumber = function (target) { + if (typeof target === 'number' && isNaN(target) === false) { + return true; + } else { + return false; + } +}; + +satus.isObject = function (target) { + return target instanceof Object && target !== null; +}; + +satus.isString = function (target) { + if (typeof target === 'string') { + return true; + } else { + return false; + } +}; + + +/*-------------------------------------------------------------- +# ON +--------------------------------------------------------------*/ + +satus.on = function (element, listeners) { + if (listeners) { + for (var type in listeners) { + var listener = listeners[type]; + + if (type === 'selectionchange') { + element = document; + } + + if (satus.isFunction(listener)) { + element.addEventListener(type, listener); + } else if (satus.isArray(listener) || satus.isObject(listener)) { + element.addEventListener(type, function (event) { + var target = this.skeleton.on[event.type], + parent = this.parentNode; + + target.parentSkeleton = this.skeleton; + target.parentElement = this; + + while (parent.componentName !== 'layers' && parent.componentName !== 'base' && parent !== document.body && parent.parentNode) { + parent = parent.parentNode; + } + + if (parent.componentName === 'layers' && target.component !== 'modal') { + parent.open(target); + } else if (this.baseProvider && this.baseProvider.layers.length === 1) { + satus.render(target, this.baseProvider.layers[0]); + } else { + satus.render(target, this.baseProvider); + } + }); + } else if (satus.isString(listener)) { + element.addEventListener(type, function () { + var match = this.skeleton.on[event.type].match(/(["'`].+["'`]|[^.()]+)/g), + target = this.baseProvider; + + for (var i = 0, l = match.length; i < l; i++) { + var key = match[i]; + + if (target.skeleton[key]) { + target = target.skeleton[key]; + } else { + if (typeof target[key] === 'function') { + target[key](); + } else { + target = target[key]; + } + } + + if (target.rendered) { + target = target.rendered; + } + } + }); + } + } + } +}; + + +/*-------------------------------------------------------------- +# PARENTIFY +--------------------------------------------------------------*/ + +satus.parentify = function (parentObject, exclude) { + for (var key in parentObject) { + if (exclude.indexOf(key) === -1) { + var child = parentObject[key]; + + child.parentObject = parentObject; + + if (typeof child === 'object' && child.component !== 'shortcut') { + this.parentify(child, exclude); + } + } + } +}; + + +/*-------------------------------------------------------------- +# PREPEND +--------------------------------------------------------------*/ + +satus.prepend = function (child, parent) { + if (this.isElement(child)) { + parent.prepend(child); + } else if (this.isObject(child)) { + this.render(child, parent, undefined, undefined, true); + } +}; + + +/*-------------------------------------------------------------- +# PROPERTIES +--------------------------------------------------------------*/ + +satus.properties = function (element, properties) { + if (properties) { + for (var key in properties) { + var property = properties[key]; + + if (['placeholder', 'title'].indexOf(key) !== -1) { + property = satus.locale.get(property); + } + + element[key] = property; + } + } +}; + + +/*-------------------------------------------------------------- +# RENDER +--------------------------------------------------------------*/ + +satus.render = function (skeleton, container, property, childrenOnly, prepend) { + var element; + + if (skeleton.component && childrenOnly !== true) { + var tagName = skeleton.component, + camelizedTagName = this.camelize(tagName), + namespaceURI = skeleton.namespaceURI; + + if (!namespaceURI) { + if (tagName === 'svg') { + namespaceURI = 'http://www.w3.org/2000/svg'; + } else if (skeleton.parentSkeleton && skeleton.parentSkeleton.namespaceURI) { + namespaceURI = skeleton.parentSkeleton.namespaceURI; + } + + skeleton.namespaceURI = namespaceURI; + } + + element = this.createElement(tagName, tagName, namespaceURI); + + skeleton.rendered = element; + element.skeleton = skeleton; + element.childrenContainer = element; + element.componentName = tagName; + + if (skeleton.variant) { + var variant = skeleton.variant; + + if (this.isFunction(variant)) { + variant = variant(); + } + + if (satus.isArray(variant)) { + for (var i = 0, l = variant.length; i < l; i++) { + element.className += ' satus-' + tagName + '--' + variant[i]; + } + } else { + element.className += ' satus-' + tagName + '--' + variant; + } + } + + if (skeleton.id) { + element.id = skeleton.id; + } + + if (container) { + element.baseProvider = container.baseProvider; + } + + this.attr(element, skeleton.attr); + this.style(element, skeleton.style); + this.data(element, skeleton.data); + this.class(element, skeleton.class); + this.properties(element, skeleton.properties); + this.on(element, skeleton.on); + + element.storage = (function () { + var parent = element, + key = skeleton.storage || property || false, + value; + + if (satus.isFunction(key)) { + key = key(); + } + + if (skeleton.storage !== false) { + if (key) { + value = satus.storage.get(key); + } + + if (skeleton.hasOwnProperty('value') && value === undefined) { + value = skeleton.value; + } + } + + return Object.defineProperties({}, { + key: { + get: function () { + return key; + }, + set: function (string) { + key = string; + } + }, + value: { + get: function () { + return value; + }, + set: function (val) { + value = val; + + if (skeleton.storage !== false) { + satus.storage.set(key, val); + + parent.dispatchEvent(new CustomEvent('change')); + } + } + } + }); + }()); + + if (this.components[camelizedTagName]) { + this.components[camelizedTagName](element, skeleton); + } + + this.text(element.childrenContainer, skeleton.text); + this.prepend(skeleton.before, element.childrenContainer); + + if (prepend) { + this.prepend(element, container); + } else { + this.append(element, container); + } + + element.dispatchEvent(new CustomEvent('render')); + + container = element.childrenContainer || element; + } + + if (!element || element.renderChildren !== false) { + for (var key in skeleton) { + var item = skeleton[key]; + + if (key !== 'parentSkeleton' && key !== 'parentElement' && key !== 'parentObject' && key !== 'before') { + if (item && item.component) { + item.parentSkeleton = skeleton; + + if (element) { + item.parentElement = element; + } + + this.render(item, container, key, undefined, prepend); + } + } + } + } + + return element; +}; + + +/*-------------------------------------------------------------- +# SORT +--------------------------------------------------------------*/ + +satus.sort = function (array, order, property) { + var type; + + if (property) { + type = typeof array[0][property]; + } else { + type = typeof array[0]; + } + + if (order !== 'desc') { + if (type === 'number') { + if (property) { + return array.sort(function (a, b) { + return a[property] - b[property]; + }); + } else { + return array.sort(function (a, b) { + return a - b; + }); + } + } else if (type === 'string') { + if (property) { + return array.sort(function (a, b) { + return a[property].localeCompare(b[property]); + }); + } else { + return array.sort(function (a, b) { + return a.localeCompare(b); + }); + } + } + } else { + if (type === 'number') { + if (property) { + return array.sort(function (a, b) { + return b[property] - a[property]; + }); + } else { + return array.sort(function (a, b) { + return b - a; + }); + } + } else if (type === 'string') { + if (property) { + return array.sort(function (a, b) { + return b[property].localeCompare(a[property]); + }); + } else { + return array.sort(function (a, b) { + return b.localeCompare(a); + }); + } + } + } +}; + + +/*-------------------------------------------------------------- +# STORAGE +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# CLEAR +--------------------------------------------------------------*/ + +satus.storage.clear = function (callback) { + this.data = {}; + + chrome.storage.local.clear(function () { + satus.events.trigger('storage-clear'); + + if (callback) { + callback(); + } + }); +}; + + +/*-------------------------------------------------------------- +# GET +--------------------------------------------------------------*/ + +satus.storage.get = function (key, callback) { + var target = this.data; + + if (typeof key !== 'string') { + return; + } + + key = key.split('/').filter(function (value) { + return value != ''; + }); + + for (var i = 0, l = key.length; i < l; i++) { + if (satus.isset(target[key[i]])) { + target = target[key[i]]; + } else { + return undefined; + } + } + + if (typeof target === 'function') { + return target(); + } else { + return target; + } +}; + + +/*-------------------------------------------------------------- +# IMPORT +--------------------------------------------------------------*/ + +satus.storage.import = function (keys, callback) { + var self = this; + + if (typeof keys === 'function') { + callback = keys; + + keys = undefined; + } + + chrome.storage.local.get(keys, function (items) { + for (var key in items) { + self.data[key] = items[key]; + } + + satus.log('STORAGE: data was successfully imported'); + + satus.events.trigger('storage-import'); + + if (callback) { + callback(items); + } + }); +}; + + +/*-------------------------------------------------------------- +# REMOVE +--------------------------------------------------------------*/ + +satus.storage.remove = function (key) { + delete this.data[key]; + + chrome.storage.local.remove(key, function () { + satus.events.trigger('storage-remove'); + }); +}; + + +/*-------------------------------------------------------------- +# SET +--------------------------------------------------------------*/ + +satus.storage.set = function (key, value, callback) { + var items = {}, + target = this.data; + + if (typeof key !== 'string') { + return; + } + + key = key.split('/').filter(function (value) { + return value != ''; + }); + + for (var i = 0, l = key.length; i < l; i++) { + var item = key[i]; + + if (i < l - 1) { + + if (target[item]) { + target = target[item]; + } else { + target[item] = {}; + + target = target[item]; + } + } else { + target[item] = value; + } + } + + for (var key in this.data) { + if (typeof this.data[key] !== 'function') { + items[key] = this.data[key]; + } + } + + chrome.storage.local.set(items, function () { + satus.events.trigger('storage-set'); + + if (callback) { + callback(); + } + }); +}; + + +/*-------------------------------------------------------------- +# ON CHANGED +--------------------------------------------------------------*/ + +satus.storage.onchanged = function (callback) { + chrome.storage.onChanged.addListener(function (changes) { + for (var key in changes) { + callback(key, changes[key].newValue); + } + }); +}; + + +/*-------------------------------------------------------------- +# LAST +--------------------------------------------------------------*/ + +satus.last = function (variable) { + if (this.isArray(variable) || this.isNodeList(variable)) { + return variable[variable.length - 1]; + } +}; + + +/*-------------------------------------------------------------- +# LOCALIZATION +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# GET +--------------------------------------------------------------*/ + +satus.locale.get = function (string) { + return this.data[string] || string; +}; + + +/*-------------------------------------------------------------- +# IMPORT +---------------------------------------------------------------- +satus.locale.import(url, onload, onsuccess); +--------------------------------------------------------------*/ + +satus.locale.import = function (code, callback, path) { + var language = code || window.navigator.language; + + if (language.indexOf('en') === 0) { + language = 'en'; + } + + if (!path) { + path = '_locales/'; + } + + satus.fetch(chrome.runtime.getURL(path + language + '/messages.json'), function (response) { + for (var key in response) { + satus.locale.data[key] = response[key].message; + } + + satus.log('LOCALE: data was successfully imported'); + + if (callback) { + callback(); + } + }, function (success) { + satus.fetch(chrome.runtime.getURL(path + 'en/messages.json'), success, function () { + success(); + }); + }); +}; + + +/*-------------------------------------------------------------- +# LOG +--------------------------------------------------------------*/ + +satus.log = function () { + console.log.apply(null, arguments); +}; + + +/*-------------------------------------------------------------- +# STYLE +--------------------------------------------------------------*/ + +satus.style = function (element, object) { + if (object) { + for (var key in object) { + element.style[key] = object[key]; + } + } +}; + + +/*-------------------------------------------------------------- +# TEXT +--------------------------------------------------------------*/ + +satus.text = function (element, value) { + if (value) { + if (satus.isFunction(value)) { + value = value(); + } + + element.appendChild(document.createTextNode(this.locale.get(value))); + } +}; +/*-------------------------------------------------------------- +>>> MODAL +---------------------------------------------------------------- +# Confirm +--------------------------------------------------------------*/ + +satus.components.modal = function (component, skeleton) { + component.scrim = component.createChildElement('div', 'scrim'); + component.surface = component.createChildElement('div', 'surface'); + + component.close = function () { + var component = this; + + this.classList.add('satus-modal--closing'); + + setTimeout(function () { + component.remove(); + + component.dispatchEvent(new CustomEvent('close')); + }, Number(satus.css(this.surface, 'animation-duration').replace(/[^0-9.]/g, '')) * 1000); + }; + + component.scrim.addEventListener('click', function () { + this.parentNode.close(); + }); + + if (satus.isset(skeleton.content)) { + component.surface.content = component.surface.createChildElement('p', 'content'); + + if (satus.isObject(skeleton.content)) { + satus.render(skeleton.content, component.surface.content); + } else { + component.surface.content.textContent = satus.locale.get(skeleton.content); + } + } else { + component.childrenContainer = component.surface; + } + + if (satus.components.modal[skeleton.variant]) { + satus.components.modal[skeleton.variant](component, skeleton); + } +}; + + +/*-------------------------------------------------------------- +# CONFIRM +--------------------------------------------------------------*/ + +satus.components.modal.confirm = function (component, skeleton) { + component.surface.actions = satus.render({ + component: 'section', + variant: 'align-end' + }, component.surface); + + if (skeleton.buttons) { + for (var key in skeleton.buttons) { + var button = satus.render(skeleton.buttons[key], component.surface.actions); + + button.modalProvider = component; + } + } else { + satus.render({ + cancel: { + component: 'button', + text: 'cancel', + properties: { + modalProvider: component, + }, + on: { + click: function () { + this.modalProvider.dispatchEvent(new CustomEvent('cancel')); + this.modalProvider.close(); + } + } + }, + ok: { + component: 'button', + text: 'ok', + properties: { + modalProvider: component, + }, + on: { + click: function () { + this.modalProvider.dispatchEvent(new CustomEvent('confirm')); + this.modalProvider.close(); + } + } + } + }, component.surface.actions); + } +}; +/*-------------------------------------------------------------- +>>> GRID +--------------------------------------------------------------*/ + +satus.components.grid = function (component, skeleton) { + console.log(component, skeleton); +}; +/*-------------------------------------------------------------- +>>> TEXT FIELD +--------------------------------------------------------------*/ + +satus.components.textField = function (component, skeleton) { + var container = component.createChildElement('div', 'container'), + input = container.createChildElement('textarea'), + display = container.createChildElement('div', 'display'), + line_numbers = display.createChildElement('div', 'line-numbers'), + pre = display.createChildElement('pre'), + selection = display.createChildElement('div', 'selection'), + cursor = display.createChildElement('div', 'cursor'), + hiddenValue = container.createChildElement('pre', 'hidden-value'); + + component.placeholder = skeleton.placeholder; + component.input = input; + component.display = display; + component.line_numbers = line_numbers; + component.pre = pre; + component.hiddenValue = hiddenValue; + component.selection = selection; + component.cursor = cursor; + component.syntax = { + current: 'text', + handlers: { + regex: function (value, target) { + var regex_token = /\[\^?]?(?:[^\\\]]+|\\[\S\s]?)*]?|\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9][0-9]*|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)|\((?:\?[:=!]?)?|(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??|[^.?*+^${[()|\\]+|./g, + char_class_token = /[^\\-]+|-|\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)/g, + char_class_parts = /^(\[\^?)(]?(?:[^\\\]]+|\\[\S\s]?)*)(]?)$/, + quantifier = /^(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??$/, + matches = value.match(regex_token); + + function create(type, string) { + var span = document.createElement('span'); + + span.className = type; + span.textContent = string; + + target.appendChild(span); + } + + for (var i = 0, l = matches.length; i < l; i++) { + var match = matches[i]; + + if (match[0] === '[') { + create('character-class', match); + } else if (match[0] === '(') { + create('group', match); + } else if (match[0] === ')') { + create('group', match); + } else if (match[0] === '\\' || match === '^') { + create('anchor', match); + } else if (quantifier.test(match)) { + create('quantifier', match); + } else if (match === '|' || match === '.') { + create('metasequence', match); + } else { + create('text', match); + } + } + } + }, + set: function (syntax) { + if (this.handlers[syntax]) { + this.current = syntax; + } else { + this.current = 'text'; + } + + pre.update(); + } + }; + component.focus = function () { + this.input.focus(); + }; + + if (satus.isset(skeleton.cols)) { + input.cols = skeleton.cols; + } + + if (satus.isset(skeleton.rows)) { + input.rows = skeleton.rows; + } + + Object.defineProperty(component, 'value', { + get: function () { + return this.input.value; + }, + set: function (value) { + this.input.value = value; + } + }); + + if (skeleton.syntax) { + component.syntax.set(skeleton.syntax); + } + + selection.setAttribute('disabled', ''); + + line_numbers.update = function () { + var component = this.parentNode.parentNode.parentNode, + count = component.input.value.split('\n').length; + + if (count !== this.children.length) { + satus.empty(this); + + for (var i = 1; i <= count; i++) { + var span = document.createElement('span'); + + span.textContent = i; + + this.appendChild(span); + } + } + + component.input.style.paddingLeft = this.offsetWidth + 'px'; + }; + + pre.update = function () { + var component = this.parentNode.parentNode.parentNode, + handler = component.syntax.handlers[component.syntax.current], + value = component.value || ''; + + for (var i = this.childNodes.length - 1; i > -1; i--) { + this.childNodes[i].remove(); + } + + if (handler) { + handler(value, this); + } else { + this.textContent = value; + } + + if (value.length === 0) { + var placeholder = component.placeholder; + + if (typeof placeholder === 'function') { + placeholder = component.placeholder(); + } else { + placeholder = satus.locale.get(placeholder); + } + + this.textContent = placeholder; + } + }; + + cursor.update = function () { + var component = this.parentNode.parentNode.parentNode, + input = component.input, + value = input.value, + rows_count = value.split('\n').length, + start = input.selectionStart, + end = input.selectionEnd, + rows = value.slice(0, start).split('\n'), + top = 0; + + this.style.animation = 'none'; + + if (input.selectionDirection === 'forward') { + component.hiddenValue.textContent = value.substring(0, end); + } else { + component.hiddenValue.textContent = value.substring(0, start); + } + + top = component.hiddenValue.offsetHeight; + + component.hiddenValue.textContent = satus.last(rows); + + top -= component.hiddenValue.offsetHeight; + + this.style.top = top + 'px'; + this.style.left = component.hiddenValue.offsetWidth + component.line_numbers.offsetWidth + 'px'; + + if (start === end) { + component.selection.setAttribute('disabled', ''); + } else { + component.selection.removeAttribute('disabled'); + + /*component.hiddenValue.textContent = value.substring(0, start); + + component.selection.style.left = component.hiddenValue.offsetWidth - input.scrollLeft + 'px'; + + component.hiddenValue.textContent = value.substring(start, end); + + component.selection.style.width = component.hiddenValue.offsetWidth + 'px';*/ + } + + this.style.animation = ''; + + component.hiddenValue.textContent = ''; + }; + + document.addEventListener('selectionchange', function (event) { + component.line_numbers.update(); + component.pre.update(); + component.cursor.update(); + }); + + input.addEventListener('input', function () { + var component = this.parentNode.parentNode; + + component.storage.value = this.value; + + component.line_numbers.update(); + component.pre.update(); + component.cursor.update(); + }); + + input.addEventListener('scroll', function (event) { + var component = this.parentNode.parentNode; + + component.display.style.top = -this.scrollTop + 'px'; + component.display.style.left = -this.scrollLeft + 'px'; + + component.line_numbers.update(); + component.pre.update(); + component.cursor.update(); + }); + + component.addEventListener('change', function () { + this.line_numbers.update(); + this.pre.update(); + this.cursor.update(); + }); + + component.value = component.storage.value || ''; + + component.addEventListener('render', function () { + component.line_numbers.update(); + component.pre.update(); + component.cursor.update(); + }); + + if (skeleton.on) { + for (var type in skeleton.on) { + input.addEventListener(type, function (event) { + this.parentNode.parentNode.dispatchEvent(new Event(event.type)); + }); + } + } +}; +/*-------------------------------------------------------------- +>>> CHART +---------------------------------------------------------------- +# Core + # Bar +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# CORE +--------------------------------------------------------------*/ + +satus.components.chart = function (component, skeleton) { + var type = skeleton.type; + + if (this.chart[type]) { + component.classList.add('satus-chart--' + type); + + this.chart[type](component, skeleton); + } +}; + + +/*-------------------------------------------------------------- +# BAR +--------------------------------------------------------------*/ + +satus.components.chart.bar = function (component, skeleton) { + var labels = skeleton.labels, + datasets = skeleton.datasets, + bars = []; + + if (satus.isFunction(labels)) { + labels = labels(); + } + + if (satus.isFunction(datasets)) { + datasets = datasets(); + } + + if (satus.isArray(labels)) { + var container = component.createChildElement('div', 'labels'); + + for (var i = 0, l = labels.length; i < l; i++) { + var label = labels[i], + section = container.createChildElement('div', 'section'); + + section.textContent = label; + } + } + + if (satus.isArray(datasets)) { + var container = component.createChildElement('div', 'bars'); + + for (var i = 0, l = datasets.length; i < l; i++) { + var dataset = datasets[i]; + + for (var j = 0, k = dataset.data.length; j < k; j++) { + if (!satus.isElement(bars[j])) { + bars.push(container.createChildElement('div', 'bar')); + } + + var piece = bars[j].createChildElement('div', 'piece'); + + piece.title = dataset.label; + piece.style.height = dataset.data[j] + '%'; + piece.style.backgroundColor = 'rgb(' + dataset.color.join(',') + ')'; + } + } + } +}; +/*-------------------------------------------------------------- +>>> SELECT +--------------------------------------------------------------*/ + +satus.components.select = function (component, skeleton) { + var content = component.createChildElement('div', 'content'); + + component.childrenContainer = content; + component.valueElement = document.createElement('span'); + component.selectElement = document.createElement('select'); + + component.valueElement.className = 'satus-select__value'; + + component.appendChild(component.valueElement); + component.appendChild(component.selectElement); + + component.options = skeleton.options || []; + + if (satus.isFunction(component.options)) { + component.options = component.options(); + } + + for (var i = 0, l = component.options.length; i < l; i++) { + var option = document.createElement('option'); + + option.value = component.options[i].value; + + satus.text(option, component.options[i].text); + + component.selectElement.appendChild(option); + } + + Object.defineProperty(component, 'value', { + get() { + return this.selectElement.value; + }, + set(value) { + this.selectElement.value = value; + } + }); + + component.render = function () { + satus.empty(this.valueElement); + + if (this.selectElement.options[this.selectElement.selectedIndex]) { + satus.text(this.valueElement, this.selectElement.options[this.selectElement.selectedIndex].text); + } + + this.dataset.value = this.value; + }; + + component.selectElement.addEventListener('change', function () { + var component = this.parentNode; + + component.storage.value = this.value; + + component.render(); + }); + + component.value = component.storage.value || component.options[0].value; + + component.render(); +}; +/*-------------------------------------------------------------- +>>> DIVIDER +--------------------------------------------------------------*/ + +satus.components.divider = function () {}; +/*-------------------------------------------------------------- +>>> SECTION +--------------------------------------------------------------*/ + +satus.components.section = function (component, skeleton) { + if (satus.isString(skeleton.title)) { + component.dataset.title = satus.locale.get(skeleton.title); + } +}; +/*-------------------------------------------------------------- +>>> BASE +--------------------------------------------------------------*/ + +satus.components.base = function (component) { + component.baseProvider = component; + component.layers = []; +}; +/*-------------------------------------------------------------- +>>> ALERT +--------------------------------------------------------------*/ + +satus.components.alert = function (component, skeleton) {}; +/*-------------------------------------------------------------- +>>> TIME +--------------------------------------------------------------*/ + +satus.components.time = function (component, skeleton) { + var select_skeleton = Object.assign({}, skeleton); + + select_skeleton.component = 'select'; + select_skeleton.options = []; + + if (satus.isFunction(select_skeleton.hour12)) { + select_skeleton.hour12 = select_skeleton.hour12(); + } + + for (var i = 0, l = 24; i < l; i++) { + var hour = i, + value = i; + + if (select_skeleton.hour12 === true && i > 12) { + hour -= 12; + } + + if (hour < 10) { + hour = '0' + hour; + value = '0' + value; + } + + if (select_skeleton.hour12 === true) { + if (i > 12) { + hour += ':00 pm'; + } else { + hour += ':00 am'; + } + } else { + hour += ':00' + } + + select_skeleton.options.push({ + text: hour, + value: value + ':00' + }); + } + + satus.components.select(component, select_skeleton); + + component.classList.add('satus-select'); +}; +/*-------------------------------------------------------------- +>>> SIDEBAR +--------------------------------------------------------------*/ + +satus.components.sidebar = function (component, skeleton) {}; +/*-------------------------------------------------------------- +>>> LAYERS +--------------------------------------------------------------*/ + +satus.components.layers = function (component, skeleton) { + component.path = []; + component.renderChildren = false; + component.baseProvider.layers.push(component); + + component.back = function () { + if (this.path.length > 1) { + this.path.pop(); + + this.open(this.path[this.path.length - 1], false); + } + }; + + component.open = function (skeleton, history) { + var previous_layer = satus.last(this.querySelectorAll('.satus-layers__layer')), + layer = this.createChildElement('div', 'layer'); + + if (history !== false) { + if (previous_layer) { + previous_layer.style.animation = 'fadeOutLeft 100ms linear forwards'; + layer.style.animation = 'fadeInRight 100ms linear forwards'; + } + + this.path.push(skeleton); + } else { + previous_layer.style.animation = 'fadeOutRight 100ms linear forwards'; + layer.style.animation = 'fadeInLeft 100ms linear forwards'; + } + + if (previous_layer) { + setTimeout(function () { + previous_layer.remove(); + }, satus.getAnimationDuration(previous_layer)); + } + + layer.skeleton = skeleton; + layer.baseProvider = this.baseProvider; + + satus.render(skeleton, layer, undefined, skeleton.component === 'layers'); + + this.dispatchEvent(new Event('open')); + }; + + component.update = function () { + var layer = this.querySelector('.satus-layers__layer'); + + satus.empty(layer); + satus.render(layer.skeleton, layer); + }; + + component.open(skeleton); +}; +/*-------------------------------------------------------------- +>>> LIST +--------------------------------------------------------------*/ + +satus.components.list = function (component, skeleton) { + for (var i = 0, l = skeleton.items.length; i < l; i++) { + var li = component.createChildElement('div', 'item'), + item = skeleton.items[i]; + + for (var j = 0, k = item.length; j < k; j++) { + var child = item[j]; + + if (satus.isObject(child)) { + satus.render(child, li); + } else { + var span = li.createChildElement('span'); + + span.textContent = satus.locale.get(child); + } + } + } +}; +/*-------------------------------------------------------------- +>>> COLOR PICKER +--------------------------------------------------------------*/ + +satus.components.colorPicker = function (component, skeleton) { + var component_content = component.createChildElement('div', 'content'), + component_value = component.createChildElement('span', 'value'); + + component.childrenContainer = component_content; + component.valueElement = component_value; + + component.className = 'satus-button'; + + component.addEventListener('click', function () { + var rgb = this.rgb, + hsl = satus.color.rgbToHsl(rgb), + s = hsl[1] / 100, + l = hsl[2] / 100; + + s *= l < .5 ? l : 1 - l; + + var v = l + s; + + s = 2 * s / (l + s); + + satus.render({ + component: 'modal', + variant: 'color-picker', + value: hsl, + parentElement: this, + + palette: { + component: 'div', + class: 'satus-color-picker__palette', + style: { + 'backgroundColor': 'hsl(' + hsl[0] + 'deg, 100%, 50%)' + }, + on: { + mousedown: function () { + var palette = this, + rect = this.getBoundingClientRect(), + cursor = this.children[0]; + + function mousemove(event) { + var hsl = palette.skeleton.parentSkeleton.storage.value, + x = event.clientX - rect.left, + y = event.clientY - rect.top, + s; + + x = Math.min(Math.max(x, 0), rect.width) / (rect.width / 100); + y = Math.min(Math.max(y, 0), rect.height) / (rect.height / 100); + + var v = 100 - y, + l = (2 - x / 100) * v / 2; + + hsl[1] = x * v / (l < 50 ? l * 2 : 200 - l * 2); + hsl[2] = l; + + cursor.style.left = x + '%'; + cursor.style.top = y + '%'; + + palette.nextSibling.children[0].style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)'; + + event.preventDefault(); + } + + function mouseup() { + window.removeEventListener('mousemove', mousemove); + window.removeEventListener('mouseup', mouseup); + } + + window.addEventListener('mousemove', mousemove); + window.addEventListener('mouseup', mouseup); + } + }, + + cursor: { + component: 'div', + class: 'satus-color-picker__cursor', + style: { + 'left': s * 100 + '%', + 'top': 100 - v * 100 + '%' + } + } + }, + section: { + component: 'section', + variant: 'color', + + color: { + component: 'div', + class: 'satus-color-picker__color', + style: { + 'backgroundColor': 'rgb(' + this.rgb.join(',') + ')' + } + }, + hue: { + component: 'slider', + class: 'satus-color-picker__hue', + storage: false, + value: hsl[0], + max: 360, + on: { + change: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + hsl = modal.storage.value; + + hsl[0] = this.values[0]; + + this.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)'; + this.parentSkeletonNode.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg, 100%, 50%)'; + } + } + } + }, + actions: { + component: 'section', + variant: 'actions', + + reset: { + component: 'button', + text: 'reset', + on: { + click: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + component = modal.parentSkeleton; + + component.rgb = component.skeleton.value; + + component.storage.value = component.rgb; + + component.valueElement.style.backgroundColor = 'rgb(' + component.rgb.join(',') + ')'; + + modal.rendered.close(); + } + } + }, + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + this.skeleton.parentSkeleton.parentSkeleton.rendered.close(); + } + } + }, + ok: { + component: 'button', + text: 'OK', + on: { + click: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + component = modal.parentSkeleton; + + component.rgb = satus.color.hslToRgb(modal.storage.value); + + component.storage.value = component.rgb; + + component.valueElement.style.backgroundColor = 'rgb(' + component.rgb.join(',') + ')'; + + modal.rendered.close(); + } + } + } + } + }, this.baseProvider.layers[0]); + }); + + component.addEventListener('render', function () { + component.rgb = this.storage.value || [0, 100, 50]; + + component_value.style.backgroundColor = 'rgb(' + component.rgb.join(',') + ')'; + }); +}; + +satus.components.colorPicker = function (component, skeleton) { + component.childrenContainer = component.createChildElement('div', 'content'); + + component.color = (function (element) { + var array; + + Object.defineProperty(element, 'value', { + get: function () { + return array; + }, + set: function (value) { + array = value; + + this.parentNode.storage.value = array; + + element.style.backgroundColor = 'rgb(' + value.join(',') + ')'; + } + }); + + element.value = component.storage.value || component.skeleton.value || [0, 0, 0]; + + return element; + })(component.createChildElement('span', 'value')); + + component.addEventListener('click', function () { + var hsl = satus.color.rgbToHsl(this.color.value), + s = hsl[1] / 100, + l = hsl[2] / 100; + + s *= l < .5 ? l : 1 - l; + + var v = l + s; + + s = 2 * s / (l + s); + + satus.render({ + component: 'modal', + variant: 'color-picker', + value: hsl, + parentElement: this, + + palette: { + component: 'div', + class: 'satus-color-picker__palette', + style: { + 'backgroundColor': 'hsl(' + hsl[0] + 'deg, 100%, 50%)' + }, + on: { + mousedown: function (event) { + if (event.button !== 0) { + return false; + } + + var palette = this, + rect = this.getBoundingClientRect(), + cursor = this.children[0]; + + function mousemove(event) { + var hsl = palette.skeleton.parentSkeleton.value, + x = event.clientX - rect.left, + y = event.clientY - rect.top, + s; + + x = Math.min(Math.max(x, 0), rect.width) / (rect.width / 100); + y = Math.min(Math.max(y, 0), rect.height) / (rect.height / 100); + + var v = 100 - y, + l = (2 - x / 100) * v / 2; + + hsl[1] = x * v / (l < 50 ? l * 2 : 200 - l * 2); + hsl[2] = l; + + cursor.style.left = x + '%'; + cursor.style.top = y + '%'; + + palette.nextSibling.children[0].style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)'; + + event.preventDefault(); + } + + function mouseup() { + window.removeEventListener('mousemove', mousemove); + window.removeEventListener('mouseup', mouseup); + } + + window.addEventListener('mousemove', mousemove); + window.addEventListener('mouseup', mouseup); + } + }, + + cursor: { + component: 'div', + class: 'satus-color-picker__cursor', + style: { + 'left': s * 100 + '%', + 'top': 100 - v * 100 + '%' + } + } + }, + section: { + component: 'section', + variant: 'color', + + color: { + component: 'div', + class: 'satus-color-picker__color', + style: { + 'backgroundColor': 'rgb(' + this.color.value.join(',') + ')' + } + }, + hue: { + component: 'slider', + class: 'satus-color-picker__hue', + storage: false, + value: hsl[0], + max: 360, + on: { + input: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + hsl = modal.value; + + hsl[0] = this.storage.value; + + this.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)'; + this.parentNode.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg, 100%, 50%)'; + } + } + } + }, + actions: { + component: 'section', + variant: 'actions', + + reset: { + component: 'button', + text: 'reset', + on: { + click: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + component = modal.parentElement; + + component.color.value = component.skeleton.value || [0, 0, 0]; + + modal.rendered.close(); + } + } + }, + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + this.skeleton.parentSkeleton.parentSkeleton.rendered.close(); + } + } + }, + ok: { + component: 'button', + text: 'OK', + on: { + click: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + component = modal.parentElement; + + component.color.value = satus.color.hslToRgb(modal.value); + + modal.rendered.close(); + } + } + } + } + }, this.baseProvider.layers[0]); + }); +}; +/*-------------------------------------------------------------- +>>> RADIO +--------------------------------------------------------------*/ + +satus.components.radio = function (component, skeleton) { + component.nativeControl = component.createChildElement('input', 'input'); + + component.createChildElement('i'); + + component.childrenContainer = component.createChildElement('div', 'content'); + + component.nativeControl.type = 'radio'; + + if (skeleton.group) { + component.storage.key = skeleton.group; + component.nativeControl.name = skeleton.group; + } + + if (skeleton.value) { + component.nativeControl.value = skeleton.value; + } + + component.storage.value = satus.storage.get(component.storage.key); + + if (satus.isset(component.storage.value)) { + component.nativeControl.checked = component.storage.value === skeleton.value; + } else if (skeleton.checked) { + component.nativeControl.checked = true; + } + + component.nativeControl.addEventListener('change', function () { + var component = this.parentNode; + + component.storage.value = this.value; + }); +}; +/*-------------------------------------------------------------- +>>> SLIDER +--------------------------------------------------------------*/ + +satus.components.slider = function (component, skeleton) { + var content = component.createChildElement('div', 'content'), + track_container = component.createChildElement('div', 'track-container'), + input = track_container.createChildElement('input', 'input'); + + component.childrenContainer = content; + component.input = input; + component.track = track_container.createChildElement('div', 'track'); + + input.type = 'range'; + input.min = skeleton.min || 0; + input.max = skeleton.max || 1; + input.step = skeleton.step || 1; + input.value = component.storage.value || skeleton.value || 0; + + input.addEventListener('input', function () { + var component = this.parentNode.parentNode; + + component.storage.value = Number(this.value); + + component.update(); + }); + + component.update = function () { + var input = this.input; + + this.track.style.width = 100 / (input.max - input.min) * (input.value - input.min) + '%'; + }; + + component.update(); + + if (skeleton.on) { + for (var type in skeleton.on) { + input.addEventListener(type, function (event) { + this.parentNode.parentNode.dispatchEvent(new Event(event.type)); + }); + } + } +}; +/*-------------------------------------------------------------- +>>> TABS +--------------------------------------------------------------*/ + +satus.components.tabs = function (component, skeleton) { + var tabs = skeleton.items, + value = skeleton.value; + + if (satus.isFunction(tabs)) { + tabs = tabs(); + } + + if (satus.isFunction(value)) { + value = value(); + } + + for (var i = 0, l = tabs.length; i < l; i++) { + var tab = tabs[i], + button = component.createChildElement('button'); + + button.addEventListener('click', function () { + var component = this.parentNode, + index = satus.elementIndex(this); + + component.value = index; + + component.style.setProperty('--satus-tabs-current', index); + }); + + satus.text(button, tab); + } + + component.style.setProperty('--satus-tabs-count', tabs.length); + component.style.setProperty('--satus-tabs-current', value || 0); +}; +/*-------------------------------------------------------------- +>>> SHORTCUT +--------------------------------------------------------------*/ + +satus.components.shortcut = function (component, skeleton) { + component.childrenContainer = component.createChildElement('div', 'content'); + component.valueElement = component.createChildElement('div', 'value'); + + component.className = 'satus-button'; + + component.render = function (parent) { + var self = this, + parent = parent || self.primary, + children = parent.children; + + satus.empty(parent); + + function createElement(name) { + var element = document.createElement('div'); + + element.className = 'satus-shortcut__' + name; + + parent.appendChild(element); + + return element; + } + + if (this.data.alt) { + createElement('key').textContent = 'Alt'; + } + + if (this.data.ctrl) { + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + createElement('key').textContent = 'Ctrl'; + } + + if (this.data.shift) { + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + createElement('key').textContent = 'Shift'; + } + + for (var code in this.data.keys) { + var key = this.data.keys[code].key, + arrows = ['ArrowUp', 'ArrowRight', 'ArrowDown', 'ArrowLeft'], + index = arrows.indexOf(key); + + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + if (index !== -1) { + createElement('key').textContent = ['↑', '→', '↓', '←'][index]; + } else if (key === ' ') { + createElement('key').textContent = '␣'; + } else if (key) { + createElement('key').textContent = key.toUpperCase(); + } + } + + if (this.data.wheel) { + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + var mouse = createElement('mouse'), + div = document.createElement('div'); + + mouse.appendChild(div); + + mouse.className += ' ' + (this.data.wheel > 0); + } + + if (this.data.click) { + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + var mouse = createElement('mouse'), + div = document.createElement('div'); + + mouse.appendChild(div); + + mouse.className += ' click'; + } + + if (this.data.middle) { + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + var mouse = createElement('mouse'), + div = document.createElement('div'); + + mouse.appendChild(div); + + mouse.className += ' middle'; + } + + if (this.data.context) { + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + var mouse = createElement('mouse'), + div = document.createElement('div'); + + mouse.appendChild(div); + + mouse.className += ' context'; + } + }; + + component.keydown = function (event) { + event.preventDefault(); + event.stopPropagation(); + + component.data = { + alt: event.altKey, + ctrl: event.ctrlKey, + shift: event.shiftKey, + keys: {} + }; + + if (['control', 'alt', 'altgraph', 'shift'].indexOf(event.key.toLowerCase()) === -1) { + component.data.keys[event.keyCode] = { + code: event.code, + key: event.key + }; + } + + component.data.wheel = 0; + + component.render(); + + return false; + }; + + if (skeleton.wheel !== false) { + component.mousewheel = function (event) { + event.stopPropagation(); + + if ( + ( + component.data.wheel === 0 && + ( + Object.keys(component.data.keys).length === 0 && + component.data.alt === false && + component.data.ctrl === false && + component.data.shift === false + ) + ) || + component.data.wheel < 0 && event.deltaY > 0 || + component.data.wheel > 0 && event.deltaY < 0) { + component.data = { + alt: false, + ctrl: false, + shift: false, + keys: {} + }; + } + + component.data.wheel = event.deltaY < 0 ? -1 : 1; + + component.render(); + + return false; + }; + } + + component.addEventListener('click', function () { + satus.render({ + component: 'modal', + properties: { + parent: this + }, + on: { + close: function () { + window.removeEventListener('keydown', component.keydown); + window.removeEventListener('wheel', component.mousewheel); + } + }, + + primary: { + component: 'div', + class: 'satus-shortcut__primary', + on: { + render: function () { + component.primary = this; + + if (component.skeleton.mouseButtons === true) { + this.addEventListener('mousedown', function (event) { + if ( + component.data.click && event.button === 0 || + component.data.middle && event.button === 1 + ) { + component.data = { + alt: false, + ctrl: false, + shift: false, + keys: {} + }; + } + + component.data.click = false; + component.data.middle = false; + component.data.context = false; + + if (event.button === 0) { + component.data.click = true; + + component.render(); + } else if (event.button === 1) { + component.data.middle = true; + + component.render(); + } + }); + + this.addEventListener('contextmenu', function (event) { + event.preventDefault(); + event.stopPropagation(); + + if (component.data.context) { + component.data = { + alt: false, + ctrl: false, + shift: false, + keys: {} + }; + } + + component.data.context = true; + component.data.middle = false; + component.data.click = false; + + component.render(); + + return false; + }); + } + + component.render(); + } + } + }, + actions: { + component: 'section', + variant: 'actions', + + reset: { + component: 'button', + text: 'reset', + on: { + click: function () { + var component = this.parentNode.parentNode.parentNode.parent; + + component.data = component.skeleton.value || {}; + + component.render(component.valueElement); + + satus.storage.remove(component.storage); + + this.parentNode.parentNode.parentNode.close(); + + window.removeEventListener('keydown', component.keydown); + window.removeEventListener('wheel', component.mousewheel); + } + } + }, + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + component.data = satus.storage.get(component.storage) || component.skeleton.value || {}; + + component.render(component.valueElement); + + this.parentNode.parentNode.parentNode.close(); + + window.removeEventListener('keydown', component.keydown); + window.removeEventListener('wheel', component.mousewheel); + } + } + }, + save: { + component: 'button', + text: 'save', + on: { + click: function () { + component.storage.value = component.data; + + component.render(component.valueElement); + + this.parentNode.parentNode.parentNode.close(); + + window.removeEventListener('keydown', component.keydown); + window.removeEventListener('wheel', component.mousewheel); + } + } + } + } + }, this.baseProvider); + + window.addEventListener('keydown', this.keydown); + window.addEventListener('wheel', this.mousewheel); + }); + + component.data = component.storage.value || { + alt: false, + ctrl: false, + shift: false, + keys: {}, + wheel: 0 + }; + + component.render(component.valueElement); +}; +/*-------------------------------------------------------------- +>>> CHECKBOX +--------------------------------------------------------------*/ + +satus.components.checkbox = function (component, skeleton) { + component.addEventListener('click', function () { + if (this.dataset.value === 'true') { + this.storage.value = false; + this.dataset.value = 'false'; + } else { + this.storage.value = true; + this.dataset.value = 'true'; + } + }); + + component.addEventListener('render', function () { + this.dataset.value = this.storage.value; + }); +}; +/*-------------------------------------------------------------- +>>> SWITCH +--------------------------------------------------------------*/ + +satus.components.switch = function (component, skeleton) { + var content = component.createChildElement('div', 'content'), + component_thumb = component.createChildElement('i'); + + component.childrenContainer = content; + + component.addEventListener('click', function () { + if (this.dataset.value === 'true') { + this.storage.value = false; + this.dataset.value = 'false'; + } else { + this.storage.value = true; + this.dataset.value = 'true'; + } + }, true); + + component.addEventListener('render', function () { + this.dataset.value = this.storage.value; + }); +}; +/*-------------------------------------------------------------- +>>> MANIFEST +--------------------------------------------------------------*/ + +satus.manifest = function () { + var object = {}; + + if (this.isset('chrome.runtime.getManifest')) { + object = chrome.runtime.getManifest(); + } + + return object; +}; +/*-------------------------------------------------------------- +>>> COLOR: +---------------------------------------------------------------- +# String to array +# RGB to HSL +# HUE to RGB +# HSL to RGB +--------------------------------------------------------------*/ + +satus.color = {}; + + +/*-------------------------------------------------------------- +# STRING TO ARRAY +--------------------------------------------------------------*/ + +satus.color.stringToArray = function (string) { + var match = string.match(/[0-9.]+/g); + + if (match) { + for (var i = 0, l = match.length; i < l; i++) { + match[i] = parseFloat(match[i]); + } + } + + return match; +}; + + +/*-------------------------------------------------------------- +# RGB TO HSL +--------------------------------------------------------------*/ + +satus.color.rgbToHsl = function (array) { + var r = array[0] / 255, + g = array[1] / 255, + b = array[2] / 255, + min = Math.min(r, g, b), + max = Math.max(r, g, b), + h = 0, + s = 0, + l = (min + max) / 2; + + if (min === max) { + h = 0; + s = 0; + } else { + var delta = max - min; + + s = l <= 0.5 ? delta / (max + min) : delta / (2 - max - min); + + if (max === r) { + h = (g - b) / delta + (g < b ? 6 : 0); + } else if (max === g) { + h = (b - r) / delta + 2; + } else if (max === b) { + h = (r - g) / delta + 4; + } + + h /= 6; + } + + h *= 360; + s *= 100; + l *= 100; + + if (array.length === 3) { + return [h, s, l]; + } else { + return [h, s, l, array[3]]; + } +}; + + +/*-------------------------------------------------------------- +# HUE TO RGB +--------------------------------------------------------------*/ + +satus.color.hueToRgb = function (array) { + var t1 = array[0], + t2 = array[1], + hue = array[2]; + + if (hue < 0) { + hue += 6; + } + + if (hue >= 6) { + hue -= 6; + } + + if (hue < 1) { + return (t2 - t1) * hue + t1; + } else if (hue < 3) { + return t2; + } else if (hue < 4) { + return (t2 - t1) * (4 - hue) + t1; + } else { + return t1; + } +}; + + +/*-------------------------------------------------------------- +# HSL TO RGB +--------------------------------------------------------------*/ + +satus.color.hslToRgb = function (array) { + var h = array[0] / 360, + s = array[1] / 100, + l = array[2] / 100, + r, g, b; + + if (s == 0) { + r = g = b = l; + } else { + var hue2rgb = function (p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + }; + + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + + return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; +}; +/*-------------------------------------------------------------- +>>> USER +---------------------------------------------------------------- +# OS + # Name + # Bitness +# Browser + # Name + # Version + # Platform + # Manifest + # Languages + # Cookies + # Flash + # Java + # Audio + # Video + # WebGL +# Device + # Screen + # RAM + # GPU + # Cores + # Touch + # Connection +--------------------------------------------------------------*/ + +satus.user = { + browser: {}, + device: {}, + os: {} +}; + +/*-------------------------------------------------------------- +# OS +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# NAME +--------------------------------------------------------------*/ + +satus.user.os.name = function () { + var app_version = navigator.appVersion; + + if (app_version.indexOf('Win') !== -1) { + if (app_version.match(/(Windows 10.0|Windows NT 10.0)/)) { + return 'Windows 10'; + } else if (app_version.match(/(Windows 8.1|Windows NT 6.3)/)) { + return 'Windows 8.1'; + } else if (app_version.match(/(Windows 8|Windows NT 6.2)/)) { + return 'Windows 8'; + } else if (app_version.match(/(Windows 7|Windows NT 6.1)/)) { + return 'Windows 7'; + } else if (app_version.match(/(Windows NT 6.0)/)) { + return 'Windows Vista'; + } else if (app_version.match(/(Windows NT 5.1|Windows XP)/)) { + return 'Windows XP'; + } else { + return 'Windows'; + } + } else if (app_version.indexOf('(iPhone|iPad|iPod)') !== -1) { + return 'iOS'; + } else if (app_version.indexOf('Mac') !== -1) { + return 'macOS'; + } else if (app_version.indexOf('Android') !== -1) { + return 'Android'; + } else if (app_version.indexOf('OpenBSD') !== -1) { + return 'OpenBSD'; + } else if (app_version.indexOf('SunOS') !== -1) { + return 'SunOS'; + } else if (app_version.indexOf('Linux') !== -1) { + return 'Linux'; + } else if (app_version.indexOf('X11') !== -1) { + return 'UNIX'; + } +}; + + +/*-------------------------------------------------------------- +# BITNESS +--------------------------------------------------------------*/ + +satus.user.os.bitness = function () { + if (navigator.appVersion.match(/(Win64|x64|x86_64|WOW64)/)) { + return '64-bit'; + } else { + return '32-bit'; + } +}; + + +/*-------------------------------------------------------------- +# BROWSER +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# NAME +--------------------------------------------------------------*/ + +satus.user.browser.name = function () { + var user_agent = navigator.userAgent; + + if (user_agent.indexOf('Opera') !== -1) { + return 'Opera'; + } else if (user_agent.indexOf('Vivaldi') !== -1) { + return 'Vivaldi'; + } else if (user_agent.indexOf('Edge') !== -1) { + return 'Edge'; + } else if (user_agent.indexOf('Chrome') !== -1) { + return 'Chrome'; + } else if (user_agent.indexOf('Safari') !== -1) { + return 'Safari'; + } else if (user_agent.indexOf('Firefox') !== -1) { + return 'Firefox'; + } else if (user_agent.indexOf('MSIE') !== -1) { + return 'IE'; + } +}; + + +/*-------------------------------------------------------------- +# VERSION +--------------------------------------------------------------*/ + +satus.user.browser.version = function () { + var browser_name = satus.user.browser.name(), + browser_version = navigator.userAgent.match(new RegExp(browser_name + '/([0-9.]+)')); + + return browser_version[1]; +}; + + +/*-------------------------------------------------------------- +# PLATFORM +--------------------------------------------------------------*/ + +satus.user.browser.platform = function () { + return navigator.platform; +}; + + +/*-------------------------------------------------------------- +# MANIFEST +--------------------------------------------------------------*/ + +satus.user.browser.manifest = function () { + return chrome.runtime.getManifest() || {}; +}; + + +/*-------------------------------------------------------------- +# LANGUAGES +--------------------------------------------------------------*/ + +satus.user.browser.languages = function () { + return navigator.languages; +}; + + +/*-------------------------------------------------------------- +# COOKIES +--------------------------------------------------------------*/ + +satus.user.browser.cookies = function () { + if (document.cookie) { + var random_cookie = 'ta{t`nX6cMXK,Wsc'; + + document.cookie = random_cookie; + + if (document.cookie.indexOf(random_cookie) !== -1) { + return true; + } + } + + return false; +}; + + +/*-------------------------------------------------------------- +# FLASH +--------------------------------------------------------------*/ + +satus.user.browser.flash = function () { + try { + if (new ActiveXObject('ShockwaveFlash.ShockwaveFlash')) { + return true; + } + } catch (error) { + if (navigator.mimeTypes['application/x-shockwave-flash']) { + return true; + } + } + + return false; +}; + + +/*-------------------------------------------------------------- +# JAVA +--------------------------------------------------------------*/ + +satus.user.browser.java = function () { + if (satus.isFunction(navigator.javaEnabled) && navigator.javaEnabled()) { + return true; + } else { + return false; + } +}; + + +/*-------------------------------------------------------------- +# AUDIO +--------------------------------------------------------------*/ + +satus.user.browser.audio = function () { + var audio = document.createElement('audio'), + types = { + mp3: 'audio/mpeg', + mp4: 'audio/mp4', + aif: 'audio/x-aiff' + }, + result = []; + + if (satus.isFunction(audio.canPlayType)) { + for (var key in types) { + var can_play_type = audio.canPlayType(types[key]); + + if (can_play_type !== '') { + result.push(key); + } + } + } + + return result; +}; + + +/*-------------------------------------------------------------- +# VIDEO +--------------------------------------------------------------*/ + +satus.user.browser.video = function () { + var video = document.createElement('video'), + types = { + ogg: 'video/ogg; codecs="theora"', + h264: 'video/mp4; codecs="avc1.42E01E"', + webm: 'video/webm; codecs="vp8, vorbis"', + vp9: 'video/webm; codecs="vp9"', + hls: 'application/x-mpegURL; codecs="avc1.42E01E"' + }, + result = []; + + if (satus.isFunction(video.canPlayType)) { + for (var key in types) { + var can_play_type = video.canPlayType(types[key]); + + if (can_play_type !== '') { + result.push(key); + } + } + } + + return result; +}; + + +/*-------------------------------------------------------------- +# WEBGL +--------------------------------------------------------------*/ + +satus.user.browser.webgl = function () { + var cvs = document.createElement('canvas'), + ctx = cvs.getContext('webgl'); + + return ctx && ctx instanceof WebGLRenderingContext; +}; + + +/*-------------------------------------------------------------- +# HARDWARE +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# SCREEN +--------------------------------------------------------------*/ + +satus.user.device.screen = function () { + if (screen) { + return screen.width + 'x' + screen.height; + } +}; + + +/*-------------------------------------------------------------- +# RAM +--------------------------------------------------------------*/ + +satus.user.device.ram = function () { + if ('deviceMemory' in navigator) { + return navigator.deviceMemory + ' GB'; + } +}; + + +/*-------------------------------------------------------------- +# GPU +--------------------------------------------------------------*/ + +satus.user.device.gpu = function () { + var cvs = document.createElement('canvas'), + ctx = cvs.getContext('webgl'); + + if ( + ctx && + ctx instanceof WebGLRenderingContext && + 'getParameter' in ctx && + 'getExtension' in ctx + ) { + var info = ctx.getExtension('WEBGL_debug_renderer_info'); + + if (info) { + return ctx.getParameter(info.UNMASKED_RENDERER_WEBGL); + } + } +}; + + +/*-------------------------------------------------------------- +# CORES +--------------------------------------------------------------*/ + +satus.user.device.cores = function () { + return navigator.deviceConcurrency; +}; + + +/*-------------------------------------------------------------- +# TOUCH +--------------------------------------------------------------*/ + +satus.user.device.touch = function () { + var result = {}; + + if ( + window.hasOwnProperty('ontouchstart') || + window.DocumentTouch && document instanceof window.DocumentTouch || + navigator.maxTouchPoints > 0 || + window.navigator.msMaxTouchPoints > 0 + ) { + result.touch = true; + result.maxTouchPoints = navigator.maxTouchPoints; + } + + return result; +}; + + +/*-------------------------------------------------------------- +# CONNECTION +--------------------------------------------------------------*/ + +satus.user.device.connection = function () { + var result = {}; + + if (typeof navigator.connection === 'object') { + result.type = navigator.connection.effectiveType || null; + + if (navigator.connection.downlink) { + result.speed = navigator.connection.downlink + ' Mbps'; + } + } + + return result; +}; +/*-------------------------------------------------------------- +# SEARCH +--------------------------------------------------------------*/ + +satus.search = function (query, object, callback) { + var elements = ['switch', 'select', 'slider', 'shortcut', 'radio', 'color-picker'], + threads = 0, + results = {}, + excluded = [ + 'baseProvider', + 'childrenContainer', + 'parentElement', + 'parentObject', + 'parentSkeleton', + 'rendered', + 'namespaceURI' + ]; + + query = query.toLowerCase(); + + function parse(items, parent) { + threads++; + + for (var key in items) { + if (excluded.indexOf(key) === -1) { + var item = items[key]; + + if (item.component) { + //console.log(key, item.component); + + if (elements.indexOf(item.component) !== -1 && key.indexOf(query) !== -1) { + results[key] = Object.assign({}, item); + } + } + + if (typeof item === 'object') { + parse(item, items); + } + } + } + + threads--; + + if (threads === 0) { + callback(results); + } + } + + parse(object); +}; diff --git a/background.js b/background.js index f326631..d35f06f 100644 --- a/background.js +++ b/background.js @@ -1,57 +1,107 @@ /*-------------------------------------------------------------- >>> BACKGROUND +---------------------------------------------------------------- +# Global variable +# Update user agent +# Messages +# Storage + # Get + # On change --------------------------------------------------------------*/ -var ext_storage = {}; - -chrome.storage.local.get(function(items) { - ext_storage = items; - - function requestListener(request) { - if (typeof request.requestHeaders === 'object') { - for (var header of request.requestHeaders) { - if (header.name.toLowerCase() === 'user-agent') { - if (ext_storage['user-agent'] && ext_storage['user-agent'] !== '') { - header.value = ext_storage['user-agent']; - } - } - } - } - - return { - requestHeaders: request.requestHeaders - }; - } - - chrome.webRequest.onBeforeSendHeaders.addListener( - requestListener, { - urls: [''] - }, ['blocking', 'requestHeaders'] - ); - - chrome.storage.onChanged.addListener(function(changes) { - for (var key in changes) { - var value = changes[key].newValue; - - ext_storage[key] = changes[key].newValue; - } - - chrome.webRequest.onBeforeSendHeaders.removeListener( - requestListener, { - urls: [''] - }, ['blocking', 'requestHeaders'] - ); - - chrome.webRequest.onBeforeSendHeaders.addListener( - requestListener, { - urls: [''] - }, ['blocking', 'requestHeaders'] - ); - }); +/*-------------------------------------------------------------- +# GLOBAL VARIABLE +--------------------------------------------------------------*/ + +var extension = {}; + + +/*-------------------------------------------------------------- +# UPDATE USER AGENT +--------------------------------------------------------------*/ + +extension.updateUserAgent = function (string) { + if (typeof string === 'string') { + chrome.declarativeNetRequest.updateDynamicRules({ + addRules: [{ + 'id': 1001, + 'priority': 1, + 'action': { + 'type': 'modifyHeaders', + 'requestHeaders': [{ + 'header': 'User-Agent', + 'operation': 'set', + 'value': string + }] + }, + 'condition': { + 'urlFilter': '*://*/*', + 'resourceTypes': [ + 'main_frame', + 'sub_frame', + 'stylesheet', + 'script', + 'image', + 'font', + 'object', + 'xmlhttprequest', + 'ping', + 'csp_report', + 'media', + 'websocket', + 'webtransport', + 'webbundle', + 'other' + ] + } + }], + removeRuleIds: [1001] + }); + } else { + chrome.declarativeNetRequest.updateDynamicRules({ + removeRuleIds: [1001] + }); + } +}; + + +/*-------------------------------------------------------------- +# MESSAGES +--------------------------------------------------------------*/ + +chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { + var action = message.action; + + if (action === 'options-page-connected') { + sendResponse({ + isPopup: sender.hasOwnProperty('tab') === false + }); + } }); + +/*-------------------------------------------------------------- +# STORAGE +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# GET +--------------------------------------------------------------*/ + + +chrome.storage.local.get(function (items) { + extension.updateUserAgent(items['user-agent']); +}); + + +/*-------------------------------------------------------------- +# ON CHANGE +--------------------------------------------------------------*/ + chrome.storage.onChanged.addListener(function (changes) { - for (var key in changes) { - ext_storage[key] = changes[key].newValue; - } + for (var key in changes) { + if (key === 'user-agent') { + extension.updateUserAgent(changes[key].newValue); + } + } }); \ No newline at end of file diff --git a/data/user-agents.js b/data/user-agents.js deleted file mode 100644 index cab86fe..0000000 --- a/data/user-agents.js +++ /dev/null @@ -1,127 +0,0 @@ -/*-------------------------------------------------------------- ->>> USER AGENTS ---------------------------------------------------------------*/ - -var user_agents = { - 'car': { - 'Tesla': 'Mozilla/5.0 (X11; GNU/Linux) AppleWebKit/537.36 (KHTML, like Gecko) Chromium/88.0.4324.150 Chrome/88.0.4324.150 Safari/537.36 Tesla/2021.4.18.2-6c676ce09ea5' - }, - 'computer': { - 'Windows': { - 'Windows 10': { - 'Chrome': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0 Safari/537.36', - 'Firefox': 'Mozilla/5.0 (Windows NT 10.0; rv:95.0) Gecko/20171102 Firefox/95.0', - 'Opera': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 OPR/79.0.4143.61', - 'Edge': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 Edg/94.0.992.31/PmaOHqHf-37', - 'Vivaldi': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.83 Safari/537.36 Vivaldi/4.2.2406.48', - 'Whale': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.232 Whale/2.10.124.26 Safari/537.36' - }, - 'Windows 8.1': { - 'Chrome': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.8948.8989 Safari/537.36', - 'Firefox': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0/10csO9CgK-99', - 'Opera': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 OPR/79.0.4143.50 (Edition Yx 02)', - 'Edge': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 Edg/94.0.992.31', - 'Vivaldi': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.122 Safari/537.36 Vivaldi/2.3.1440.60', - 'Whale': 'Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.229 Whale/2.10.123.42 Safari/537.36' - }, - 'Windows 8': { - 'Chrome': 'Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.48 CitizenFX/1.0.0.4590 Safari/537.36', - 'Firefox': 'Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0/10csO9CgK-99', - 'Opera': 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 OPR/79.0.4143.66', - 'Edge': 'Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 Edg/94.0.992.31', - 'Vivaldi': 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.143 Safari/537.36 Vivaldi/1.95.1077.45', - 'Whale': 'Mozilla/5.0 (Windows NT 6.2; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Whale/2.8.108.15 Safari/537.36' - }, - 'Windows 7': { - 'Chrome': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.48 CitizenFX/1.0.0.4590 Safari/537.36', - 'Firefox': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0/CZyfq6zd2FAGsZdS0An', - 'Opera': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 OPR/79.0.4143.66 (Edition Campaign 70)', - 'Edge': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 Edg/94.0.992.31', - 'Vivaldi': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.183 Safari/537.36 Vivaldi/6969562071AB', - 'Whale': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.232 Whale/2.10.124.26 Safari/537.36', - 'Internet Explorer': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.2)' - }, - 'Windows Vista': { - 'Chrome': 'Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36', - 'Firefox': 'Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9.1b2pre) Gecko/20081026 Minefield/3.1b2pre', - 'Opera': 'Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 OPR/78.0.4093.231', - 'Edge': 'Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299', - 'Vivaldi': 'Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36 Vivaldi/1.0.435.46', - 'Internet Explorer': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; BOIE9;FRFR)' - }, - 'Windows XP': { - 'Chrome': 'Mozilla/5.0 (Windows XP) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36', - 'Firefox': 'Mozilla/5.0 (Windows; U; Windows XP) Gecko MultiZilla/1.6.1.0a', - 'Opera': 'Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.99', - 'Internet Explorer': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)' - }, - 'Windows 2000': { - 'Firefox': 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8) Gecko/20051111 Firefox/1.5', - 'Opera': 'Opera/9.80 (Windows NT 5.0; U; MRA 5.9 (build 4930); ru) Presto/2.10.229 Version/11.62', - 'Internet Explorer': 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)' - }, - 'Windows 98': { - 'Firefox': 'Mozilla/5.0 (Windows; U; Win98; bg; rv:1.8.1.10) Gecko/20100526 Firefox/3.7a5pre', - 'Opera': 'Opera/8.20.(Windows 98; ro-RO) Presto/2.9.186 Version/11.00', - 'Internet Explorer': 'Mozilla/4.0 (compatible; MSIE 4.01; MSN 2.5; Windows 98)' - } - }, - 'macOS': { - 'Safari': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.7 Safari/605.1.15', - 'Chrome': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4653.2 Safari/537.36', - 'Firefox': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4; rv:87.0) Gecko/20100101 Firefox/87.0', - 'Opera': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 OPR/79.0.4143.50', - 'Edge': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 Edg/94.0.992.31', - 'Vivaldi': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.88 Safari/537.36 Vivaldi/2.4.1488.36', - 'Whale': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Whale/2.8.108.15 Safari/537.36' - }, - 'Linux': { - 'Chrome': 'Mozilla/5.0 (Linux; 7.0; P2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36', - 'Firefox': 'Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.8) Gecko/20051111 Firefox/54.0', - 'Vivaldi': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Vivaldi/4.1.2369.21' - } - }, - 'gameConsole': { - 'PlayStation': { - 'PlayStation 4': 'Mozilla/5.0 (PlayStation 4 5.05) AppleWebKit/601.2 (KHTML, like Gecko)', - 'PlayStation 3': 'Mozilla/5.0 (PLAYSTATION 3 4.81) AppleWebKit/531.22.8 (KHTML, like Gecko)', - 'PlayStation Vita': 'Mozilla/5.0 (PlayStation Vita 3.50) AppleWebKit/537.73 (KHTML, like Gecko) Silk/3.2', - 'PlayStation Portable': 'Mozilla/4.0 (PSP (PlayStation Portable); 2.00)' - }, - 'Xbox': { - 'Xbox One': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299', - 'Xbox 360': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox)' - }, - 'Nintendo': { - 'Nintendo Switch': 'Mozilla/5.0 (Nintendo Switch; WebApplet) AppleWebKit/606.4 (KHTML, like Gecko) NF/6.0.1.18.3 NintendoBrowser/5.1.0.21481', - 'Nintendo Wii U': 'Mozilla/5.0 (Nintendo WiiU) AppleWebKit/536.30 (KHTML, like Gecko) NX/3.0.4.2.13 NintendoBrowser/4.3.2.11274.US', - 'Nintendo Wii': 'Opera/9.30 (Nintendo Wii; U; ; 3642; en)', - 'Nintendo 3DS': 'Mozilla/5.0 (New Nintendo 3DS like iPhone) AppleWebKit/536.30 (KHTML, like Gecko) NX/3.0.0.5.22 Mobile NintendoBrowser/1.10.10166.US' - } - }, - 'phone': { - 'Android': { - 'Chrome': 'Mozilla/5.0 (Linux; Android 10; W-V680-OPE) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Mobile Safari/537.36', - 'Firefox': 'Mozilla/5.0 (Android 10.0; Mobile; rv:90.0) Gecko/90.0 Firefox/90.0', - 'Opera': 'Mozilla/5.0 (Linux; Android 11; CPH1979) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Mobile Safari/537.36 OPR/64.3.3282.60839', - 'Edge': 'Mozilla/5.0 (Linux; Android 11; Redmi Note 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Mobile Safari/537.36 EdgA/93.0.961.62' - }, - 'iOS': { - 'Safari': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.2 Mobile/15E148 Safari/604.1', - 'Chrome': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/93.0.4577.78 Mobile/15E148 Safari/604.1', - 'Firefox': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/37.0 Mobile/15E148 Safari/605.1.15' - }, - 'Symbian': { - 'Opera': 'Opera/9.80 (S60; SymbOS; Opera Mobi/SYB-1204232254; U; en-GB) Presto/2.10.254 Version/12.00', - 'Nokia Browser': 'Nokia7610/2.0 (5.0509.0) SymbianOS/7.0s Series60/2.1 Profile/MIDP-2.0 Configuration/CLDC-1.0', - 'Ovi 2.0': 'Mozilla/5.0 (Series40; Nokia200/11.64; Profile/MIDP-2.1 Configuration/CLDC-1.1) Gecko/20100401 S40OviBrowser/2.0.2.68.14' - } - }, - 'tv': { - 'Google TV': 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/90.0.4430.212 Large Screen Safari/534.24 GoogleTV/092754youtube.com/tv#', - 'Samsung TV': 'Mozilla/5.0 (SMART-TV; Linux; Tizen 2.4.0) AppleWebkit/538.1 (KHTML, like Gecko) SamsungBrowser/1.1 TV Safari/538.1' - }, - 'watch': { - 'watchOS': 'atc/1.0 watchOS/7.5 model/Watch3,3 hwp/t8004 build/18T567 (6; dt:155)' - } -}; \ No newline at end of file diff --git a/manifest.json b/manifest.json index 77d9a67..8d00254 100644 --- a/manifest.json +++ b/manifest.json @@ -1,28 +1,26 @@ { - "manifest_version": 2, + "manifest_version": 3, "name": "User-Agent", - "version": "2.0", + "version": "3.0", "default_locale": "en", "icons": { - "16": "assets/icons/16.png", - "32": "assets/icons/32.png", - "48": "assets/icons/48.png", - "128": "assets/icons/128.png" - }, + "16": "assets/icons/16.png", + "32": "assets/icons/32.png", + "48": "assets/icons/48.png", + "128": "assets/icons/128.png" + }, "background": { - "scripts": [ - "background.js" - ] + "service_worker": "background.js" }, - "browser_action": { - "default_popup": "popup.html" + "action": { + "default_popup": "options-page/index.html" }, - "options_page": "options.html", + "options_page": "options-page/index.html", + "host_permissions": [ + "" + ], "permissions": [ "storage", - "", - "webNavigation", - "webRequest", - "webRequestBlocking" + "declarativeNetRequest" ] -} +} \ No newline at end of file diff --git a/options-page/functions.js b/options-page/functions.js new file mode 100644 index 0000000..928784b --- /dev/null +++ b/options-page/functions.js @@ -0,0 +1,187 @@ +/*-------------------------------------------------------------- +>>> FUNCTIONS +---------------------------------------------------------------- +# Render +# Export settings +# Import settings +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# RENDER +--------------------------------------------------------------*/ + +extension.icons = { + car: 'M18.92 5.01C18.72 4.42 18.16 4 17.5 4h-11c-.66 0-1.21.42-1.42 1.01L3 11v8c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-8l-2.08-5.99zM6.5 15c-.83 0-1.5-.67-1.5-1.5S5.67 12 6.5 12s1.5.67 1.5 1.5S7.33 15 6.5 15zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM5 10l1.5-4.5h11L19 10H5z', + computer: 'M20 18c1.1 0 1.99-.9 1.99-2L22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2H0v2h24v-2h-4zM4 6h16v10H4V6z', + gameConsole: 'm21.58 16.09-1.09-7.66A3.996 3.996 0 0 0 16.53 5H7.47C5.48 5 3.79 6.46 3.51 8.43l-1.09 7.66C2.2 17.63 3.39 19 4.94 19c.68 0 1.32-.27 1.8-.75L9 16h6l2.25 2.25c.48.48 1.13.75 1.8.75 1.56 0 2.75-1.37 2.53-2.91zM11 11H9v2H8v-2H6v-1h2V8h1v2h2v1zm4-1c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm2 3c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z', + phone: 'M17 1.01 7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z', + tv: 'M21 3H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.1-.9-2-2-2zm0 14H3V5h18v12z', + watch: 'M20 12c0-2.54-1.19-4.81-3.04-6.27L16 0H8l-.95 5.73C5.19 7.19 4 9.45 4 12s1.19 4.81 3.05 6.27L8 24h8l.96-5.73A7.976 7.976 0 0 0 20 12zM6 12c0-3.31 2.69-6 6-6s6 2.69 6 6-2.69 6-6 6-6-2.69-6-6z' +}; + +extension.render = function (object, skeleton) { + skeleton.section = { + component: 'section', + variant: 'card' + }; + + for (var key in object) { + var item = object[key]; + + if (typeof item === 'object') { + skeleton.section[key] = { + component: 'button', + text: key, + on: { + click: {} + } + }; + + if (extension.icons[key]) { + skeleton.section[key].before = { + component: 'svg', + attr: { + 'fill': 'currentColor', + 'viewBox': '0 0 24 24' + }, + + path: { + component: 'path', + attr: { + 'd': extension.icons[key] + } + } + }; + } + + extension.render(item, skeleton.section[key].on.click); + } else { + skeleton.section[key] = { + component: 'radio', + group: 'user-agent', + text: key, + value: item + }; + } + } +}; + + +/*-------------------------------------------------------------- +# EXPORT SETTINGS +--------------------------------------------------------------*/ + +extension.exportSettings = function () { + if (location.href.indexOf('action=export-settings') !== -1) { + satus.render({ + component: 'modal', + variant: 'confirm', + content: 'areYouSureYouWantToExportTheData', + buttons: { + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + this.modalProvider.close(); + } + } + }, + ok: { + component: 'button', + text: 'ok', + on: { + click: function () { + try { + var blob = new Blob([JSON.stringify(satus.storage.data)], { + type: 'application/json;charset=utf-8' + }); + + chrome.permissions.request({ + permissions: ['downloads'] + }, function (granted) { + if (granted) { + chrome.downloads.download({ + url: URL.createObjectURL(blob), + filename: 'user-agent.json', + saveAs: true + }, function () { + setTimeout(function () { + close(); + }, 1000); + }); + } + }); + } catch (error) { + console.error(error); + } + } + } + } + } + }, extension.skeleton.rendered); + } +}; + + +/*-------------------------------------------------------------- +# IMPORT SETTINGS +--------------------------------------------------------------*/ + +extension.importSettings = function () { + if (location.href.indexOf('action=import-settings') !== -1) { + satus.render({ + component: 'modal', + variant: 'confirm', + content: 'areYouSureYouWantToImportTheData', + buttons: { + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + this.modalProvider.close(); + } + } + }, + ok: { + component: 'button', + text: 'ok', + on: { + click: function () { + var input = document.createElement('input'); + + input.type = 'file'; + + input.addEventListener('change', function () { + var file_reader = new FileReader(); + + file_reader.onload = function () { + var data = JSON.parse(this.result); + + for (var key in data) { + satus.storage.set(key, data[key]); + } + + setTimeout(function () { + chrome.runtime.sendMessage({ + action: 'import-settings' + }); + + setTimeout(function () { + close(); + }, 128); + }, 256); + }; + + file_reader.readAsText(this.files[0]); + }); + + input.click(); + } + } + } + } + }, extension.skeleton.rendered); + } +}; \ No newline at end of file diff --git a/options-page/index.css b/options-page/index.css new file mode 100644 index 0000000..c1e5220 --- /dev/null +++ b/options-page/index.css @@ -0,0 +1,95 @@ +/*-------------------------------------------------------------- +>>> OPTIONS PAGE +---------------------------------------------------------------- +# Fonts + # Regular + # Medium + # Bold +# Theme +# Vertical menu +# Tab mode +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# REGULAR +--------------------------------------------------------------*/ + +@font-face { + font-family: Roboto; + + src: url(../assets/fonts/Roboto-Regular.ttf); +} + + +/*-------------------------------------------------------------- +# MEDIUM +--------------------------------------------------------------*/ + +@font-face { + font-family: Roboto; + font-weight: 500; + + src: url(../assets/fonts/Roboto-Medium.ttf); +} + + +/*-------------------------------------------------------------- +# BOLD +--------------------------------------------------------------*/ + +@font-face { + font-family: Roboto; + font-weight: 700; + + src: url(../assets/fonts/Roboto-Bold.ttf); +} + + +/*-------------------------------------------------------------- +# THEME +--------------------------------------------------------------*/ + +.satus-base { + --satus-light: 255, 255, 255; + --satus-primary: #c92c46; + --satus-base-background: #1b1528; + --satus-base-foreground: #fafafa; + --satus-header-background: #473172; + --satus-header-shadow: transparent; + --satus-section-background: #2e2343; + --satus-section-border: #2e2343; + --satus-modal-background: #473172; + --satus-modal-shadow: 0 1px 4px #222; + --satus-text-field-background: #2e2343; +} + + +/*-------------------------------------------------------------- +# VERTICAL MENU +--------------------------------------------------------------*/ + +.satus-modal--vertical-menu .satus-modal__surface { + max-width: 200px; +} + + +/*-------------------------------------------------------------- +# TAB MODE +--------------------------------------------------------------*/ + + +body[tab] { + overflow: hidden; + + width: 100vw; + height: 100vh; +} + +body[tab] .satus-base { + width: 100%; + height: 100%; +} + +body[tab] .satus-alert { + display: none; +} \ No newline at end of file diff --git a/options-page/index.html b/options-page/index.html new file mode 100644 index 0000000..8abf39d --- /dev/null +++ b/options-page/index.html @@ -0,0 +1,25 @@ + + + + + + User-Agent + + + + + + + + + + + \ No newline at end of file diff --git a/options-page/index.js b/options-page/index.js new file mode 100644 index 0000000..8f8ea43 --- /dev/null +++ b/options-page/index.js @@ -0,0 +1,129 @@ +/*-------------------------------------------------------------- +>>> OPTIONS PAGE +---------------------------------------------------------------- +# Global variable +# Initialization +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# GLOBAL VARIABLE +--------------------------------------------------------------*/ + +var extension = {}; + + +/*-------------------------------------------------------------- +# INITIALIZATION +--------------------------------------------------------------*/ + +satus.storage.import(function (items) { + var language = items.language; + + if (!language) { + language = window.navigator.language; + } + + satus.locale.import(language, function () { + satus.fetch(chrome.runtime.getURL('assets/data/user-agent.json'), function (response) { + extension.render(response, extension.skeleton.main.layers); + + extension.skeleton.main.layers.section.custom = { + component: 'button', + text: 'custom', + before: { + component: 'svg', + attr: { + 'fill': 'currentColor', + 'viewBox': '0 0 24 24' + }, + + path: { + component: 'path', + attr: { + 'd': 'M5 4v3h5.5v12h3V7H19V4z' + } + } + }, + on: { + click: { + component: 'section', + variant: 'transparent-card', + style: { + 'height': 'calc(100% - 24px)', + 'margin': '12px' + }, + + textField: { + component: 'text-field', + storage: 'user-agent', + style: { + 'height': '100%' + } + } + } + } + }; + + extension.skeleton.main.layers.section.reset = { + component: 'button', + text: 'reset', + before: { + component: 'svg', + attr: { + 'fill': 'currentColor', + 'viewBox': '0 0 24 24' + }, + + path: { + component: 'path', + attr: { + 'd': 'm13 11.6 2.5 2.5q.275.275.275.7 0 .425-.275.7-.275.275-.7.275-.425 0-.7-.275l-2.8-2.8q-.15-.15-.225-.338-.075-.187-.075-.387V8q0-.425.288-.713Q11.575 7 12 7t.713.287Q13 7.575 13 8ZM12 21q-3.025 0-5.425-1.788-2.4-1.787-3.225-4.662-.125-.45.088-.85.212-.4.662-.5.425-.1.763.187.337.288.462.713.65 2.2 2.513 3.55Q9.7 19 12 19q2.925 0 4.962-2.038Q19 14.925 19 12t-2.038-4.963Q14.925 5 12 5q-1.725 0-3.225.8T6.25 8H8q.425 0 .713.287Q9 8.575 9 9t-.287.712Q8.425 10 8 10H4q-.425 0-.712-.288Q3 9.425 3 9V5q0-.425.288-.713Q3.575 4 4 4t.713.287Q5 4.575 5 5v1.35q1.275-1.6 3.113-2.475Q9.95 3 12 3q1.875 0 3.513.712 1.637.713 2.85 1.925 1.212 1.213 1.925 2.85Q21 10.125 21 12t-.712 3.512q-.713 1.638-1.925 2.85-1.213 1.213-2.85 1.926Q13.875 21 12 21Z' + } + } + }, + on: { + click: { + component: 'modal', + variant: 'confirm', + content: 'allYourSettingsWillBeErasedAndCanTBeRecovered', + buttons: { + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + this.modalProvider.close(); + } + } + }, + reset: { + component: 'button', + text: 'reset', + on: { + click: function () { + satus.storage.clear(function () { + close(); + }); + } + } + } + } + } + } + }; + + satus.render(extension.skeleton); + + extension.exportSettings(); + extension.importSettings(); + }); + }, '_locales/'); +}); + +chrome.runtime.sendMessage({ + action: 'options-page-connected' +}, function (response) { + if (response.isPopup === false) { + document.body.setAttribute('tab', ''); + } +}); \ No newline at end of file diff --git a/options-page/skeleton.js b/options-page/skeleton.js new file mode 100644 index 0000000..0d6c959 --- /dev/null +++ b/options-page/skeleton.js @@ -0,0 +1,492 @@ +/*-------------------------------------------------------------- +>>> SKELETON +---------------------------------------------------------------- +# Base +# Header +# Main +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# BASE +--------------------------------------------------------------*/ + +extension.skeleton = { + component: 'base' +}; + + +/*-------------------------------------------------------------- +# HEADER +--------------------------------------------------------------*/ + +extension.skeleton.header = { + component: 'header', + + sectionStart: { + component: 'section', + variant: 'align-start', + + back: { + component: 'button', + variant: 'icon', + attr: { + 'hidden': 'true' + }, + on: { + click: 'main.layers.back' + }, + + svg: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'stroke-width': '1.5', + 'stroke': 'currentColor', + 'fill': 'none' + }, + + path: { + component: 'path', + attr: { + 'd': 'M14 18l-6-6 6-6' + } + } + } + }, + title: { + component: 'span', + variant: 'title' + } + }, + sectionEnd: { + component: 'section', + variant: 'align-end', + + menu: { + component: 'button', + variant: 'icon', + on: { + click: { + component: 'modal', + variant: 'vertical-menu', + + language: { + component: 'select', + on: { + change: function () { + var language = satus.storage.get('language'); + + if (!language || language === 'default') { + language = window.navigator.language; + } + + satus.locale.import(language, function () { + var layers = document.querySelector('.satus-layers'); + + extension.skeleton.main.layers.rendered.dispatchEvent(new CustomEvent('open')); + + satus.empty(layers.firstChild); + + satus.render(satus.last(layers.path), layers.firstChild, undefined, true); + }, '_locales/'); + } + }, + options: [{ + value: "en", + text: "English" + }, { + value: "es", + text: "Español (España)" + }, { + value: "es-419", + text: "Español (Latinoamérica)" + }, { + value: "es-US", + text: "Español (US)" + }, { + value: "ru", + text: "Русский" + }, { + value: "de", + text: "Deutsch" + }, { + value: "pt-PT", + text: "Português" + }, { + value: "pt", + text: "Português (Brasil)" + }, { + value: "fr", + text: "Français" + }, { + value: "pl", + text: "Polski" + }, { + value: "ja", + text: "日本語" + }, { + value: "af", + text: "Afrikaans" + }, { + value: "az", + text: "Azərbaycan" + }, { + value: "id", + text: "Bahasa Indonesia" + }, { + value: "ms", + text: "Bahasa Malaysia" + }, { + value: "bs", + text: "Bosanski" + }, { + value: "ca", + text: "Català" + }, { + value: "cs", + text: "Čeština" + }, { + value: "da", + text: "Dansk" + }, { + value: "et", + text: "Eesti" + }, { + value: "eu", + text: "Euskara" + }, { + value: "fil", + text: "Filipino" + }, { + value: "fr-CA", + text: "Français (Canada)" + }, { + value: "gl", + text: "Galego" + }, { + value: "hr", + text: "Hrvatski" + }, { + value: "zu", + text: "IsiZulu" + }, { + value: "is", + text: "Íslenska" + }, { + value: "it", + text: "Italiano" + }, { + value: "sw", + text: "Kiswahili" + }, { + value: "lv", + text: "Latviešu valoda" + }, { + value: "lt", + text: "Lietuvių" + }, { + value: "hu", + text: "Magyar" + }, { + value: "nl", + text: "Nederlands" + }, { + value: "no", + text: "Norsk" + }, { + value: "uz", + text: "O‘zbek" + }, { + value: "ro", + text: "Română" + }, { + value: "sq", + text: "Shqip" + }, { + value: "sk", + text: "Slovenčina" + }, { + value: "sl", + text: "Slovenščina" + }, { + value: "sr-Latn", + text: "Srpski" + }, { + value: "fi", + text: "Suomi" + }, { + value: "sv", + text: "Svenska" + }, { + value: "vi", + text: "Tiếng Việt" + }, { + value: "tr", + text: "Türkçe" + }, { + value: "be", + text: "Беларуская" + }, { + value: "bg", + text: "Български" + }, { + value: "ky", + text: "Кыргызча" + }, { + value: "kk", + text: "Қазақ Тілі" + }, { + value: "mk", + text: "Македонски" + }, { + value: "mn", + text: "Монгол" + }, { + value: "sr", + text: "Српски" + }, { + value: "uk", + text: "Українська" + }, { + value: "el", + text: "Ελληνικά" + }, { + value: "hy", + text: "Հայերեն" + }, { + value: "iw", + text: "עברית" + }, { + value: "ur", + text: "اردو" + }, { + value: "ar", + text: "العربية" + }, { + value: "fa", + text: "فارسی" + }, { + value: "ne", + text: "नेपाली" + }, { + value: "mr", + text: "मराठी" + }, { + value: "hi", + text: "हिन्दी" + }, { + value: "bn", + text: "বাংলা" + }, { + value: "pa", + text: "ਪੰਜਾਬੀ" + }, { + value: "gu", + text: "ગુજરાતી" + }, { + value: "ta", + text: "தமிழ்" + }, { + value: "te", + text: "తెలుగు" + }, { + value: "kn", + text: "ಕನ್ನಡ" + }, { + value: "ml", + text: "മലയാളം" + }, { + value: "si", + text: "සිංහල" + }, { + value: "th", + text: "ภาษาไทย" + }, { + value: "lo", + text: "ລາວ" + }, { + value: "my", + text: "ဗမာ" + }, { + value: "ka", + text: "ქართული" + }, { + value: "am", + text: "አማርኛ" + }, { + value: "km", + text: "ខ្មែរ" + }, { + value: "zh-CN", + text: "中文 (简体)" + }, { + value: "zh-TW", + text: "中文 (繁體)" + }, { + value: "zh-HK", + text: "中文 (香港)" + }, { + value: "ko", + text: "한국어" + }], + before: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'fill': 'currentColor' + }, + + path: { + component: 'path', + attr: { + 'd': 'M12.9 15l-2.6-2.4c1.8-2 3-4.2 3.8-6.6H17V4h-7V2H8v2H1v2h11.2c-.7 2-1.8 3.8-3.2 5.3-1-1-1.7-2.1-2.3-3.3h-2c.7 1.6 1.7 3.2 3 4.6l-5.1 5L4 19l5-5 3.1 3.1.8-2zm5.6-5h-2L12 22h2l1.1-3H20l1.1 3h2l-4.5-12zm-2.6 7l1.6-4.3 1.6 4.3H16z' + } + } + }, + text: 'language' + }, + export: { + component: 'button', + text: 'export', + before: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'fill': 'none', + 'stroke': 'currentColor', + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round', + 'stroke-width': '2' + }, + + path: { + component: 'path', + attr: { + 'd': 'M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12' + } + } + }, + on: { + click: function () { + if (location.href.indexOf('options-page/index.html?action=export-settings') !== -1) { + extension.exportSettings(); + } else { + chrome.tabs.create({ + url: 'options-page/index.html?action=export-settings' + }); + } + } + } + }, + import: { + component: 'button', + text: 'import', + before: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'fill': 'none', + 'stroke': 'currentColor', + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round', + 'stroke-width': '2' + }, + + path: { + component: 'path', + attr: { + 'd': 'M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3' + } + } + }, + on: { + click: function () { + if (location.href.indexOf('options-page/index.html?action=import-settings') !== -1) { + extension.importSettings(); + } else { + chrome.tabs.create({ + url: 'options-page/index.html?action=import-settings' + }); + } + } + } + } + } + }, + + svg: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'stroke-width': '2', + 'stroke': 'currentColor', + 'fill': 'none' + }, + + circle1: { + component: 'circle', + attr: { + 'cx': '12', + 'cy': '5.25', + 'r': '0.45' + } + }, + circle2: { + component: 'circle', + attr: { + 'cx': '12', + 'cy': '12', + 'r': '0.45' + } + }, + circle3: { + component: 'circle', + attr: { + 'cx': '12', + 'cy': '18.75', + 'r': '0.45' + } + } + } + } + } +}; + + +/*-------------------------------------------------------------- +# MAIN +--------------------------------------------------------------*/ + +extension.skeleton.main = { + component: 'main', + + layers: { + component: 'layers', + on: { + open: function () { + var skeleton = satus.last(this.path), + section = this.baseProvider.skeleton.header.sectionStart, + title = satus.manifest().name; + + if (skeleton.parentSkeleton) { + if (skeleton.parentSkeleton.label) { + title = skeleton.parentSkeleton.label.text; + } else if (skeleton.parentSkeleton.text) { + title = skeleton.parentSkeleton.text; + } + } + + section.back.rendered.hidden = this.path.length <= 1; + section.title.rendered.innerText = satus.locale.get(title); + + var vertical_menu = document.querySelector('.satus-modal--vertical-menu'); + + if (vertical_menu) { + vertical_menu.close(); + } + } + }, + + toolbar: {} + } +}; \ No newline at end of file diff --git a/options.html b/options.html deleted file mode 100644 index 6e501b6..0000000 --- a/options.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - ImprovedTube - - - - - - - - - - - \ No newline at end of file diff --git a/popup.css b/popup.css deleted file mode 100644 index 37873ac..0000000 --- a/popup.css +++ /dev/null @@ -1,158 +0,0 @@ -/*--------------------------------------------------------------- ->>> USER AGENT ------------------------------------------------------------------ -# ----------------------------------------------------------------*/ - -html { - --satus-primary: #764e7e; - --satus-modal-background: #3b273f; - --satus-modal-text: #faeaed; - --satus-header-background: #ed2c4c; - --satus-header-text: #faeaed; - --satus-layers-background: #28102d; - --satus-layers-text: #faeaed; - --satus-section-card-background: #3b273f; - --satus-hover: rgba(255, 255, 255, .12); - --satus-switch-track: #28102d; - --satus-switch-track--active: #ed2c4c; - --satus-switch-thumb: #c6cad2; - --satus-tabs: #3b273f; - --satus-pluviam-background: #fff; - --satus-pluviam-opacity: .12; -} - -.satus-header { - font-weight: 600; - z-index: 1; - box-shadow: 0 2px 0 #b81430; -} - -.satus-header .satus-h1--title { - font-size: 16px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - text-shadow: 2px 1px #b81430; - flex: 1; -} - -.satus-header .satus-button>.satus-span { - position: absolute; - left: 18px; - width: 3px; - height: 3px; - border-radius: 50%; - background: currentColor; - box-shadow: 2px 1px #b81430; -} - -.satus-header .satus-button>.satus-span:nth-child(1) { - top: 11px; -} - -.satus-header .satus-button>.satus-span:nth-child(2) { - top: 19px; -} - -.satus-header .satus-button>.satus-span:nth-child(3) { - bottom: 10px; -} - -.satus-modal--vertical .satus-modal__surface { - position: absolute; - top: 8px; - right: 8px; - left: auto; - min-width: 180px; - max-width: 180px; - transform-origin: right top; - padding: 8px 0; -} - -.satus-modal--vertical .satus-button { - display: flex; - height: 36px; - padding: 0 16px; - align-items: center; -} - -.satus-modal--vertical .satus-button svg { - width: 20px; - height: 18px; - margin: 0 14px 0 0; - opacity: .75; - fill: none; - stroke: var(--satus-primary); - flex: 0 0 20px; -} - -.satus-modal--vertical .satus-button .satus-span { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; -} - -.satus-section--column { - width: 100%; - height: 100%; -} - -.satus-textarea { - font-family: monospace; - font-size: inherit; - width: calc(100% - 32px); - height: calc(100% - 32px); - padding: 8px; - resize: none; - color: inherit; - border-radius: 8px; - outline: none; - background: var(--satus-section-card-background); - appearance: none; - margin: 16px; - box-sizing: border-box; -} - - -/*-------------------------------------------------------------- -# STAR US ON GITHUB ---------------------------------------------------------------*/ - -.star-us-on-github { - font-size: 13px; - font-weight: 500; - position: absolute; - bottom: 16px; - left: 50%; - width: 100%; - height: auto; - min-height: auto; - padding: 0; - cursor: pointer; - transition: 150ms; - transform: translateX(-50%); - text-align: center; - text-decoration: none; - color: #9595b2; - justify-content: center; -} - -[hide-star-us-on-github=true] .star-us-on-github { - display: none; -} - -.star-us-on-github svg { - position: relative; - top: 4px; - width: 20px; - height: 20px; -} - -.star-us-on-github span:first-child { - margin: 0 4px 0 0; -} - -.star-us-on-github span:last-child { - margin: 0 0 0 4px; -} \ No newline at end of file diff --git a/popup.html b/popup.html deleted file mode 100644 index e66affa..0000000 --- a/popup.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - ImprovedTube - - - - - - - - - - - \ No newline at end of file diff --git a/popup.js b/popup.js deleted file mode 100644 index e5bb3a1..0000000 --- a/popup.js +++ /dev/null @@ -1,724 +0,0 @@ -/*-------------------------------------------------------------- ->>> POPUP: ----------------------------------------------------------------- -# Skeleton -# Initialization ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# SKELETON ---------------------------------------------------------------*/ - -var skeleton = { - component: 'base', - - header: { - component: 'header', - - section_1: { - component: 'section', - variant: 'align-start', - - back: { - component: 'button', - attr: { - 'hidden': 'true' - }, - on: { - click: 'layers.back' - }, - pluviam: true, - - svg: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'none', - 'stroke-width': '1.5', - 'stroke': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'M14 18l-6-6 6-6' - } - } - } - }, - title: { - component: 'h1', - variant: 'title' - } - }, - section_2: { - component: 'section', - variant: 'align-end', - - menu: { - component: 'button', - on: { - click: { - component: 'modal', - variant: 'vertical', - - settings: { - component: 'button', - on: { - click: { - section: { - component: 'section', - variant: 'card', - on: { - render: function () { - document.querySelector('.satus-modal').close(); - } - }, - - appearance: { - component: 'button', - on: { - click: { - section: { - component: 'section', - variant: 'card', - - hide_made_with_love: { - component: 'switch', - text: 'hideStarUs', - storage: 'hide-star-us-on-github' - } - } - } - }, - - svg: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'M7 16c.6 0 1 .5 1 1a2 2 0 0 1-2 2h-.5a4 4 0 0 0 .5-2c0-.6.5-1 1-1M18.7 3a1 1 0 0 0-.7.3l-9 9 2.8 2.7 9-9c.3-.4.3-1 0-1.4l-1.4-1.3a1 1 0 0 0-.7-.3zM7 14a3 3 0 0 0-3 3c0 1.3-1.2 2-2 2 1 1.2 2.5 2 4 2a4 4 0 0 0 4-4 3 3 0 0 0-3-3z' - } - } - }, - label: { - component: 'span', - text: 'appearance' - } - }, - languages: { - component: 'button', - on: { - click: { - section: { - component: 'section', - variant: 'card', - - language: { - text: 'language', - component: 'select', - on: { - change: function (name, value) { - var self = this; - - satus.ajax('_locales/' + this.querySelector('select').value + '/messages.json', function (response) { - try { - response = JSON.parse(response); - - for (var key in response) { - satus.locale.strings[key] = response[key].message; - } - - self.base.skeleton.header.section_1.title.rendered.textContent = satus.locale.get('languages'); - - self.base.skeleton.layers.rendered.update(); - } catch (error) { - console.log(error); - //close(); - } - }); - } - }, - options: [{ - value: 'en', - text: 'English' - }, { - value: 'ko', - text: '한국어' - }, { - value: 'es', - text: 'Español (España)' - }, { - value: 'ru', - text: 'Русский' - }, { - value: 'de', - text: 'Deutsch' - }, { - value: 'zh_TW', - text: '中文 (繁體)' - }, { - value: 'pt_PT', - text: 'Português' - }, { - value: 'pt_BR', - text: 'Português (Brasil)' - }, { - value: 'zh_CN', - text: '中文 (简体)' - }, { - value: 'fr', - text: 'Français' - }, { - value: 'ja', - text: '日本語' - }, { - value: 'tr', - text: 'Türkçe' - }, { - value: 'tr', - text: 'Italiano' - }, { - value: 'nl', - text: 'Nederlands' - }, { - value: 'ar', - text: 'العربية' - }, { - value: 'id', - text: 'Bahasa Indonesia' - }, { - value: 'nb', - text: 'Norsk' - }, { - value: 'nb_NO', - text: 'Norsk (Bokmål)' - }, { - value: 'el', - text: 'Ελληνικά' - }, { - value: 'bn', - text: 'বাংলা' - }, { - value: 'hin', - text: 'हिन्दी' - }, { - value: 'sk', - text: 'Slovenčina' - }, { - value: 'pl', - text: 'Polski' - }] - } - } - } - }, - - svg: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'M12.9 15l-2.6-2.4c1.8-2 3-4.2 3.8-6.6H17V4h-7V2H8v2H1v2h11.2c-.7 2-1.8 3.8-3.2 5.3-1-1-1.7-2.1-2.3-3.3h-2c.7 1.6 1.7 3.2 3 4.6l-5.1 5L4 19l5-5 3.1 3.1.8-2zm5.6-5h-2L12 22h2l1.1-3H20l1.1 3h2l-4.5-12zm-2.6 7l1.6-4.3 1.6 4.3H16z' - } - } - }, - label: { - component: 'span', - text: 'languages' - } - }, - about: { - component: 'button', - on: { - click: { - component: 'span', - - on: { - render: function () { - var component = this, - manifest = chrome.runtime.getManifest(), - user = satus.user(), - skeleton_about = { - extension_section_label: { - component: 'span', - class: 'satus-section--label', - text: 'extension' - }, - extension_section: { - component: 'section', - variant: 'card', - - list: { - component: 'list', - items: [ - ['version', manifest.version], - ['permissions', manifest.permissions.join(', ').replace('https://www.youtube.com/', 'YouTube')] - ] - } - }, - browser_section_label: { - component: 'span', - class: 'satus-section--label', - text: 'browser' - }, - browser_section: { - component: 'section', - variant: 'card', - - list: { - component: 'list', - items: [ - ['name', user.browser.name], - ['version', user.browser.version], - ['platform', user.browser.platform], - ['videoFormats', { - component: 'span', - on: { - render: function () { - var formats = []; - - for (var key in user.browser.video) { - if (user.browser.video[key] !== false) { - formats.push(key); - } - } - - this.textContent = formats.join(', '); - } - } - }], - ['audioFormats', { - component: 'span', - on: { - render: function () { - var formats = []; - - for (var key in user.browser.audio) { - if (user.browser.audio[key] !== false) { - formats.push(key); - } - } - - this.textContent = formats.join(', '); - } - } - }], - ['flash', !!user.browser.flash ? 'true' : 'false'] - ] - } - }, - os_section_label: { - component: 'span', - class: 'satus-section--label', - text: 'os' - }, - os_section: { - component: 'section', - variant: 'card', - - list: { - component: 'list', - items: [ - ['name', user.os.name], - ['type', user.os.type] - ] - } - }, - device_section_label: { - component: 'span', - class: 'satus-section--label', - text: 'device' - }, - device_section: { - component: 'section', - variant: 'card', - - list: { - component: 'list', - items: [ - ['screen', user.device.screen], - ['cores', user.device.cores], - ['gpu', user.device.gpu], - ['ram', user.device.ram] - ] - } - } - }; - - setTimeout(function () { - satus.render(skeleton_about, component.parentNode); - - component.remove(); - }); - } - } - } - }, - - svg: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'M11 7h2v2h-2zm0 4h2v6h-2zm1-9a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16z' - } - } - }, - label: { - component: 'span', - text: 'about' - } - } - } - } - }, - - icon: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'var(--satus-primary)' - }, - - path: { - component: 'path', - attr: { - 'd': 'M19.4 13l.1-1v-1l2-1.6c.2-.2.3-.5.2-.7l-2-3.4c-.2-.3-.4-.3-.6-.3l-2.5 1-1.7-1-.4-2.6c0-.2-.3-.4-.5-.4h-4c-.3 0-.5.2-.5.4l-.4 2.7c-.6.2-1.1.6-1.7 1L5 5c-.2-.1-.4 0-.6.2l-2 3.4c0 .3 0 .5.2.7l2 1.6a8 8 0 0 0 0 2l-2 1.6c-.2.2-.3.5-.2.7l2 3.4c.2.3.4.3.6.3l2.5-1 1.7 1 .4 2.6c0 .2.2.4.5.4h4c.3 0 .5-.2.5-.4l.4-2.7c.6-.2 1.1-.6 1.7-1l2.5 1c.2.1.4 0 .6-.2l2-3.4c0-.2 0-.5-.2-.7l-2-1.6zM12 15.5a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7z' - } - } - }, - label: { - component: 'span', - text: 'settings' - } - } - } - }, - pluviam: true, - - dot_1: { - component: 'span' - }, - dot_2: { - component: 'span' - }, - dot_3: { - component: 'span' - } - } - } - }, - layers: { - component: 'layers', - on: { - open: function () { - var parent = this.path[this.path.length - 1].parent, - section = this.base.skeleton.header.section_1, - title = 'User Agent'; - - if (parent) { - if (parent.label) { - title = parent.label.text; - } else if (parent.text) { - title = parent.text; - } - } - - section.back.rendered.hidden = this.path.length <= 1; - section.title.rendered.innerText = satus.locale.get(title); - } - } - } -}; - - -/*-------------------------------------------------------------- -# INITIALIZATION ---------------------------------------------------------------*/ - -satus.storage.attributes = { - 'hide-star-us-on-github': true -}; - -satus.storage.import(function (items) { - var language = items.language || window.navigator.language || 'en'; - - satus.ajax('_locales/' + language + '/messages.json', function (response) { - try { - response = JSON.parse(response); - - for (var key in response) { - satus.locale.strings[key] = response[key].message; - } - - function parse(target, source) { - source.section = { - component: 'section', - variant: 'card' - }; - - source = source.section; - - for (var key in target) { - var item = target[key]; - - if (typeof item === 'object') { - source[key] = { - component: 'button', - text: key, - on: { - click: {} - } - }; - - parse(item, source[key].on.click); - } else { - source[key] = { - component: 'radio', - group: 'user-agent', - text: key, - value: item - }; - } - } - } - - parse(user_agents, skeleton.layers); - - delete skeleton.layers.section.car.text; - - skeleton.layers.section.car.icon = { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'M18.92 5.01C18.72 4.42 18.16 4 17.5 4h-11c-.66 0-1.21.42-1.42 1.01L3 11v8c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-8l-2.08-5.99zM6.5 15c-.83 0-1.5-.67-1.5-1.5S5.67 12 6.5 12s1.5.67 1.5 1.5S7.33 15 6.5 15zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM5 10l1.5-4.5h11L19 10H5z' - } - } - }; - - skeleton.layers.section.car.label = { - component: 'span', - text: 'car' - }; - - delete skeleton.layers.section.computer.text; - - skeleton.layers.section.computer.icon = { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'M20 18c1.1 0 1.99-.9 1.99-2L22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2H0v2h24v-2h-4zM4 6h16v10H4V6z' - } - } - }; - - skeleton.layers.section.computer.label = { - component: 'span', - text: 'computer' - }; - - delete skeleton.layers.section.gameConsole.text; - - skeleton.layers.section.gameConsole.icon = { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'm21.58 16.09-1.09-7.66A3.996 3.996 0 0 0 16.53 5H7.47C5.48 5 3.79 6.46 3.51 8.43l-1.09 7.66C2.2 17.63 3.39 19 4.94 19c.68 0 1.32-.27 1.8-.75L9 16h6l2.25 2.25c.48.48 1.13.75 1.8.75 1.56 0 2.75-1.37 2.53-2.91zM11 11H9v2H8v-2H6v-1h2V8h1v2h2v1zm4-1c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm2 3c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z' - } - } - }; - - skeleton.layers.section.gameConsole.label = { - component: 'span', - text: 'gameConsole' - }; - - delete skeleton.layers.section.phone.text; - - skeleton.layers.section.phone.icon = { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'M17 1.01 7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z' - } - } - }; - - skeleton.layers.section.phone.label = { - component: 'span', - text: 'phone' - }; - - delete skeleton.layers.section.tv.text; - - skeleton.layers.section.tv.icon = { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'M21 3H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.1-.9-2-2-2zm0 14H3V5h18v12z' - } - } - }; - - skeleton.layers.section.tv.label = { - component: 'span', - text: 'tv' - }; - - delete skeleton.layers.section.watch.text; - - skeleton.layers.section.watch.icon = { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'M20 12c0-2.54-1.19-4.81-3.04-6.27L16 0H8l-.95 5.73C5.19 7.19 4 9.45 4 12s1.19 4.81 3.05 6.27L8 24h8l.96-5.73A7.976 7.976 0 0 0 20 12zM6 12c0-3.31 2.69-6 6-6s6 2.69 6 6-2.69 6-6 6-6-2.69-6-6z' - } - } - }; - - skeleton.layers.section.watch.label = { - component: 'span', - text: 'watch' - }; - - skeleton.layers.section.custom = { - component: 'button', - on: { - click: { - component: 'section', - variant: 'column', - - textarea: { - component: 'textarea', - storage: 'user-agent', - properties: { - placeholder: '...' - }, - on: { - render: function () { - this.value = satus.storage.get(this.skeleton.storage) || ''; - }, - keydown: function () { - var self = this; - - setTimeout(function () { - satus.storage.set(self.skeleton.storage, self.value); - }); - } - } - } - } - }, - - icon: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'M5 4v3h5.5v12h3V7H19V4z' - } - } - }, - label: { - component: 'span', - text: 'custom' - } - }; - - skeleton.layers.star_us_on_github = { - component: 'a', - class: 'star-us-on-github', - attr: { - target: '_blank', - href: 'https://github.com/victor-savinov/user-agent' - }, - - span_1: { - component: 'span', - text: 'Star us' - }, - svg: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': '#ed2c4c' - }, - - path: { - component: 'path', - attr: { - 'd': 'm14.43 10-1.47-4.84c-.29-.95-1.63-.95-1.91 0L9.57 10H5.12c-.97 0-1.37 1.25-.58 1.81l3.64 2.6-1.43 4.61c-.29.93.79 1.68 1.56 1.09l3.69-2.8 3.69 2.81c.77.59 1.85-.16 1.56-1.09l-1.43-4.61 3.64-2.6c.79-.57.39-1.81-.58-1.81h-4.45z' - } - } - }, - span_2: { - component: 'span', - text: 'on GitHub' - } - }; - - satus.render(skeleton); - } catch (error) { - console.error(error); - } - }, function (success) { - satus.ajax('_locales/en/messages.json', success); - }); -}); \ No newline at end of file diff --git a/py/locale.py b/py/locale.py index 10b38b0..f484f75 100644 --- a/py/locale.py +++ b/py/locale.py @@ -1,22 +1,23 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # >>> TABLE OF CONTENTS: -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # 1.0 Import modules # 2.0 Lower camel case # 3.0 Get list of files # 4.0 Add item # 5.0 Remove item -# 6.0 Decode -# 7.0 Add locales -# 8.0 Initialization -# -------------------------------------------------------------- +# 6.0 Change key +# 7.0 Decode +# 8.0 Upgrade +# 9.0 Initialization +# ------------------------------------------------------------------------------ -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # 1.0 IMPORT MODULES -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ import io import json @@ -26,9 +27,9 @@ import sys -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # 2.0 LOWER CAMEL CASE -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ def lowerCamelCase(string): string = re.sub(r"(-|_)+", ' ', string).title() @@ -37,21 +38,21 @@ def lowerCamelCase(string): return string[0].lower() + string[1:] -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # 3.0 GET LIST OF FILES -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ -def getListOfFiles(dirName): +def getListOfFiles(path): allFiles = list() - for entry in os.listdir(dirName): - fullPath = os.path.join(dirName, entry) + for entry in os.listdir(path): + fullPath = os.path.join(path, entry) if not os.path.isdir(fullPath): allFiles.append(fullPath) - for entry in os.listdir(dirName): - fullPath = os.path.join(dirName, entry) + for entry in os.listdir(path): + fullPath = os.path.join(path, entry) if os.path.isdir(fullPath): allFiles = allFiles + getListOfFiles(fullPath) @@ -59,9 +60,9 @@ def getListOfFiles(dirName): return allFiles -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # 4.0 ADD ITEM -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ def addItem(allFiles): message = input('Enter your message: ') @@ -75,14 +76,13 @@ def addItem(allFiles): data[camelized_message] = {'message': message} json_file.seek(0) - json.dump(data, json_file, ensure_ascii=False, indent=4, - sort_keys=True) + json.dump(data, json_file, ensure_ascii=False, indent=4, sort_keys=True) json_file.truncate() -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # 5.0 REMOVE ITEM -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ def removeItem(allFiles): key = input('Enter your key (lowerCamelCase): ') @@ -100,9 +100,31 @@ def removeItem(allFiles): json_file.truncate() -# -------------------------------------------------------------- -# 6.0 DECODE -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ +# 6.0 CHANGE KEY +# ------------------------------------------------------------------------------ + +def changeKey(allFiles): + old_key = input('Enter key: ') + new_key = input('Enter new key: ') + + for keyFile in allFiles: + with open(keyFile, 'r+') as file: + data = json.load(file) + + if old_key in data: + data[new_key] = data[old_key] + + del data[old_key] + + file.seek(0) + json.dump(data, file, ensure_ascii=False, indent=4, sort_keys=True) + file.truncate() + + +# ------------------------------------------------------------------------------ +# 7.0 DECODE +# ------------------------------------------------------------------------------ def decodeCharacters(allFiles): for keyFile in allFiles: @@ -115,11 +137,11 @@ def decodeCharacters(allFiles): json_file.truncate() -# -------------------------------------------------------------- -# 7.0 ADD LOCALES -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ +# 8.0 UPGRADE +# ------------------------------------------------------------------------------ -def addLocales(): +def upgrade(): locales = [ 'am', 'ar', @@ -176,24 +198,49 @@ def addLocales(): 'zh_TW' ] + if os.path.exists('../_locales/en/messages.json'): + file = open('../_locales/en/messages.json', 'r+') + + default_locale = json.load(file) + + file.close() + else: + default_locale = {} + for locale in locales: - if not os.path.exists('../_locales/' + locale): - pathlib.Path('../_locales/' + locale).mkdir(parents=True, - exist_ok=True) + path = '../_locales/' + locale - file = io.open('../_locales/' + locale + '/messages.json', - mode='w', encoding='utf-8') + if not os.path.exists(path): + pathlib.Path(path).mkdir(parents=True, exist_ok=True) - file.write('{}') + file = io.open(path + '/messages.json', mode='w', encoding='utf-8') + json.dump(default_locale, file, ensure_ascii=False, indent=4, sort_keys=True) + file.close() + else: + with open(path + '/messages.json', 'r+') as file: + data = json.load(file) + + file.seek(0) + + for key in default_locale: + if (key in data) == False: + data[key] = default_locale[key] + + json.dump(data, file, ensure_ascii=False, indent=4, sort_keys=True) + + file.truncate() + + file.close() - print(locale) +# ------------------------------------------------------------------------------ +# 9.0 INITIALIZATION +# ------------------------------------------------------------------------------ -# -------------------------------------------------------------- -# 8.0 INITIALIZATION -# -------------------------------------------------------------- +if not os.path.exists('../_locales/'): + pathlib.Path('../_locales/').mkdir(parents=True, exist_ok=True) allFiles = getListOfFiles('../_locales/') @@ -204,5 +251,7 @@ def addLocales(): removeItem(allFiles) elif arg == '-decode': decodeCharacters(allFiles) - elif arg == '-generate': - addLocales() \ No newline at end of file + elif arg == '-change-key': + changeKey(allFiles) + elif arg == '-upgrade': + upgrade() \ No newline at end of file diff --git a/satus.css b/satus.css deleted file mode 100644 index eb8c652..0000000 --- a/satus.css +++ /dev/null @@ -1,1147 +0,0 @@ - -/*-------------------------------------------------------------- ->>> THEMES: ----------------------------------------------------------------- -# Default ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# DEFAULT ---------------------------------------------------------------*/ - -html { - --satus-primary: #ff4158; - --satus-switch-background: rgba(0,0,0,.08); - --satus-header-background: #fff; - --satus-header-text: #777; - --satus-layers-background: #f7f7f6; - --satus-layers-text: #777; - --satus-section-card-background: #fff; - --satus-modal-background: #fff; - --satus-modal-text: #777; - --satus-hover: rgba(0, 0, 0, .04); - - --satus-switch-track: #b8b8b8; - --satus-switch-track--active: var(--satus-primary); - --satus-switch-thumb: #fff; - - --satus-tabs: #fff; -} -/*-------------------------------------------------------------- ->>> COLOR PICKER ---------------------------------------------------------------*/ - -.satus-color-picker { - font-size: inherit; - position: relative; - display: flex; - box-sizing: border-box; - margin: 0; - cursor: pointer; - color: inherit; - border: none; - outline: none; - background-color: var(--satus-theme-button); - justify-content: space-between; - -webkit-tap-highlight-color: transparent; - align-items: center; - -webkit-appearance: none; -} - -.satus-color-picker__value { - width: 22px; - height: 22px; - border: 2px solid rgba(255, 255, 255, .4); - border-radius: 50%; -} - -.satus-modal--color-picker { - position: relative; -} - -.satus-modal--color-picker .satus-modal__surface { - display: flex; - flex-direction: column; - align-items: center; -} - -.satus-modal--color-picker canvas { - width: 256px; - height: 256px; -} - -.satus-color-picker__dim { - position: absolute; - width: 256px; - height: 256px; - pointer-events: none; - opacity: 0; - border-radius: 50%; - background: #000; -} - -.satus-color-picker__cursor { - position: absolute; - width: 5px; - height: 5px; - transform: translate(-50%, -50%); - pointer-events: none; - border: 1px solid #fff; - border-radius: 50%; - box-shadow: 0 0 0 1px #000; -} - -.satus-color-picker__slider .satus-slider__container { - height: 18px; -} - -.satus-color-picker__slider .satus-slider__track-container { - top: calc(50% - 9px); - height: 18px; -} - -.satus-color-picker__slider .satus-slider__track-container::before { - height: 16px; - opacity: 1; - border: 1px solid #bfbfbf; - border-radius: 4px; - background: linear-gradient(90deg, #fff, #000); -} - -.satus-color-picker__slider .satus-slider__track { - background: transparent; -} - -.satus-color-picker__slider .satus-slider__thumb { - top: 0; - height: 18px; - border-radius: 4px; - background: #fff; - box-shadow: 0 0 2px rgb(0, 0, 0, .2); -} - -.satus-color-picker__slider .satus-slider__thumb:before { - display: none; -} - -.satus-color-picker__actions { - display: flex; - width: 100%; - justify-content: flex-end; -} - -.satus-color-picker__actions .satus-button { - height: 32px; - margin: 8px 4px 0; - border-radius: 8px; - background: rgba(0, 0, 0, .15); -} - -.satus-color-picker__actions .satus-button:hover { - background: rgba(0, 0, 0, .25); -} -/*-------------------------------------------------------------- -# MAIN ---------------------------------------------------------------*/ - -.satus-main { - color: var(--satus-main-text); - background: var(--satus-main-background); - overflow-y: auto; - box-sizing: border-box; -} -/*-------------------------------------------------------------- ->>> TABS ---------------------------------------------------------------*/ - -.satus-tabs { - position: relative; - display: flex; - overflow: hidden; - box-sizing: border-box; - width: calc(100% - 16px); - margin: 16px 8px 4px; - border: 1px solid var(--satus-tabs); - border-radius: 18px; -} - -.satus-tabs__selection { - position: absolute; - z-index: 0; - left: 0; - width: 50%; - height: 32px; - transition: left .25s; - border-radius: 18px; - background: var(--satus-tabs); - box-shadow: 1px 0 4px rgb(0,0,0,.8); -} - -.satus-tabs__button { - background: transparent; - border: none; - font-family: inherit; - font-weight: 500; - font-size: 12px; - color: inherit; - height: 32px; - flex: 1; - text-transform: uppercase; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - position: relative; - z-index: 1; - padding: 0 16px; -} - -.satus-tabs__button:hover { - cursor: pointer; -} -/*-------------------------------------------------------------- ->>> RADIO ---------------------------------------------------------------*/ -/*-------------------------------------------------------------- -# BUTTON ---------------------------------------------------------------*/ - -.satus-button { - font: inherit; - position: relative; - overflow: hidden; - height: 48px; - margin: 0; - padding: 8px; - color: var(--satus-button-text, inherit); - border: none; - background: var(--satus-button-background, transparent); - appearance: none; - text-align: left; -} - -.satus-button:hover { - cursor: pointer; - background-color: var(--satus-hover); -} - -.satus-button>* { - pointer-events: none; -} - -.satus-header .satus-button { - width: 40px; - min-width: 40px; - height: 40px; - padding: 8px; - color: inherit; - border-radius: 50%; -} - -.satus-header .satus-section--align-start>* { - margin-right: 8px; -} -/*-------------------------------------------------------------- ->>> LIST: ---------------------------------------------------------------*/ - -.satus-list { - list-style: none; - margin: 0; -} - -.satus-list__item { - display: flex; - align-items: center; - justify-content: space-between; - min-height: 48px; -} - -.satus-list__item>*:last-child { - text-align: right; -} -/*-------------------------------------------------------------- ->>> SECTION: ----------------------------------------------------------------- -# ---------------------------------------------------------------*/ - -.satus-section { - display: flex; - flex-wrap: wrap; - box-sizing: border-box; -} - -.satus-section--align-start { - justify-content: flex-start; -} - -.satus-section--align-end { - justify-content: flex-end; -} - -.satus-section--column { - flex-direction: column; -} - -.satus-header>.satus-section { - align-items: center; -} - -.satus-section--card { - flex-direction: column; - width: calc(100% - 24px); - max-width: 900px; - margin: 12px auto 0; - padding: 8px 0; - border: 1px solid rgba(0,0,0,.1); - border-radius: 8px; - background: var(--satus-section-card-background); - color: var(--satus-section-card-text); - box-sizing: border-box; -} - -.satus-section--card:last-child { - margin: 12px auto; -} - -.satus-section--card>* { - min-height: 48px; - padding: 0 16px; - text-align: left; - box-sizing: border-box; - width: 100%; -} - -.satus-section--card>.satus-switch, -.satus-section--card>.satus-select, -.satus-section--card>.satus-slider, -.satus-section--card>.satus-radio -{ - display: flex; - justify-content: space-between; - align-items: center; -} - -.satus-section--card>.satus-button:hover, -.satus-section--card>.satus-switch:hover, -.satus-section--card>.satus-select:hover, -.satus-section--card>.satus-slider:hover, -.satus-section--card>.satus-radio:hover -{ - background-color: var(--satus-hover); -} - -.satus-section--card>.satus-button { - display: flex; - padding: 0 16px; - align-items: center; -} - -.satus-section--card>.satus-button>svg { - width: 20px; - margin: 2px 16px 0 0; - color: var(--satus-primary); -} - -.satus-section--label, -.satus-h2--section-label { - font-size: 14px; - display: block; - max-width: 900px; - margin: 16px 16px 8px; - width: 100%; - font-weight: 600; -} -/*-------------------------------------------------------------- -# SCROLLBAR ---------------------------------------------------------------*/ - -::-webkit-scrollbar { - width: 4px; -} - -::-webkit-scrollbar:hover { - width: 8px; -} - -::-webkit-scrollbar-thumb { - background: rgba(0, 0, 0, .3); -} -/*-------------------------------------------------------------- ->>> MODAL ---------------------------------------------------------------*/ - -.satus-modal { - position: absolute; - z-index: 100; - top: 0; - left: 0; - display: flex; - width: 100%; - height: 100vh; - justify-content: center; - align-items: center; -} - -.satus-modal__scrim { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - animation: modalFadeIn 150ms linear forwards; - opacity: 0; - background: rgba(0, 0, 0, .2); - backdrop-filter: blur(8px); -} - -.satus-modal__surface { - font-size: 14px; - display: flex; - overflow-y: auto; - flex-direction: column; - width: 95%; - min-width: 240px; - max-width: 560px; - max-height: 80%; - margin: 0 16px; - padding: 8px 16px; - transform: scale(.8); - animation: modalZoomIn 150ms linear forwards; - animation-delay: 20ms; - opacity: 0; - color: var(--satus-modal-text); - border-radius: 6px; - background-color: var(--satus-modal-background); - box-shadow: inset 0 -1px 1px 1px rgb(0, 0, 0, .1), 0 2px 6px rgb(0, 0, 0, .15); -} - -.satus-modal__surface .satus-section--actions { - display: flex; - justify-content: flex-end; - align-items: center; - margin-top: 16px; -} - -.satus-modal__surface .satus-section--actions .satus-button { - height: 32px; - margin-left: 8px; - border-radius: 4px; - padding: 0 8px; -} - -.satus-modal--closing .satus-modal__scrim { - animation: modalFadeOut 70ms linear forwards; -} - -.satus-modal--closing .satus-modal__surface { - animation: modalZoomOut 70ms linear forwards; -} - - -/*-------------------------------------------------------------- -# ANIMATIONS ---------------------------------------------------------------*/ - -@keyframes modalFadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -@keyframes modalFadeOut { - from { - opacity: 1; - } - to { - opacity: 0; - } -} - -@keyframes modalZoomIn { - from { - transform: scale(.8); - opacity: 0; - } - to { - transform: scale(1); - opacity: 1; - } -} - -@keyframes modalZoomOut { - from { - transform: scale(1); - opacity: 1; - } - to { - transform: scale(.8); - opacity: 0; - } -} -/*-------------------------------------------------------------- ->>> SWITCH ----------------------------------------------------------------- -# Container -# Track -# Thumb ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# CONTAINER ---------------------------------------------------------------*/ - -.satus-switch { - font: inherit; - display: flex; - transition: background-color 75ms; - color: inherit; - border: none; - outline: none; - background-color: transparent; - justify-content: space-between; - align-items: center; -} - -.satus-switch:hover { - cursor: pointer; -} - - -/*-------------------------------------------------------------- -# TRACK ---------------------------------------------------------------*/ - -.satus-switch > i { - width: 38px; - height: 20px; - transition: background-color 150ms; - border-radius: 20px; - background-color: var(--satus-switch-track); - flex: 0 0 38px; -} - -.satus-section--card .satus-switch > i { - margin-left: 16px; -} - -.satus-switch[data-value='true'] > i { - background-color: var(--satus-switch-track--active); -} - - -/*-------------------------------------------------------------- -# THUMB ---------------------------------------------------------------*/ - -.satus-switch > i::before { - display: block; - width: 16px; - height: 16px; - margin: 2px; - content: ''; - transition: transform 150ms cubic-bezier(.4, 0, .2, 1); - border-radius: 50%; - background-color: var(--satus-switch-thumb); - will-change: transform; -} - -.satus-switch[data-value='true'] > i::before { - transform: translateX(18px); -} -/*-------------------------------------------------------------- ->>> SLIDER: ----------------------------------------------------------------- -# ---------------------------------------------------------------*/ - -.satus-slider { - position: relative; - display: flex; - flex-direction: column; - box-sizing: border-box; - width: 100%; - min-height: 64px; - padding: 0 16px; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - outline: none; - align-items: flex-start; - justify-content: center; -} - -.satus-slider:hover { - cursor: pointer; - background-color: rgba(0, 0, 0, .04); -} - - -/* LABEL */ - -.satus-slider__label { - cursor: default; -} - -.satus-slider>input { - position: absolute; - z-index: 1; - top: 0; - left: 0; - box-sizing: border-box; - width: 100%; - height: 100%; - margin: 0; - padding: 0; - opacity: 0; -} - - -/* TRACK */ - -.satus-slider__container { - position: relative; - width: 100%; - height: 12px; - margin: 8px 0 0; -} - -.satus-slider__track-container { - position: absolute; - top: calc(50% - 1px); - width: 100%; - height: 2px; - pointer-events: none; -} - -.satus-slider__track-container::before { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 2px; - content: ''; - opacity: .26; - background-color: var(--satus-primary); -} - -.satus-slider__track { - position: relative; - width: 0; - height: 100%; - background-color: var(--satus-primary); - will-change: width; -} - -.satus-slider:not(.satus-slider--dragging) .satus-slider__track { - transition: width 100ms ease-out; -} - -.satus-slider__thumb { - position: absolute; - top: -5px; - right: -12px; - width: 12px; - height: 12px; - border-radius: 50%; - background-color: var(--satus-primary); - box-shadow: 0 1px 5px rgba(0, 0, 0, .15); -} - -.satus-slider .satus-slider__thumb::before { - font-size: 13px; - position: absolute; - top: -34px; - left: 50%; - visibility: hidden; - box-sizing: border-box; - min-width: 28px; - padding: 4px 4px; - content: attr(data-value); - transform: translateX(-50%); - text-align: center; - pointer-events: none; - color: #fff; - border-radius: 4px; - background: var(--satus-theme-tooltip); -} - -.satus-slider:hover .satus-slider__thumb::before, -.satus-slider>input:focus .satus-slider__container .satus-slider__thumb::before { - visibility: visible; -} - -.satus-slider__ring { - position: absolute; - top: -11px; - right: -18px; - width: 24px; - height: 24px; - transition: 100ms; - transform: scale(0); - opacity: 0; - border-radius: 50%; - background-color: var(--satus-primary); -} - -.satus-slider>input:focus+.satus-slider__container .satus-slider__ring { - transform: scale(1); - opacity: .25; -} -/*-------------------------------------------------------------- ->>> SHORTCUT: ----------------------------------------------------------------- -# ---------------------------------------------------------------*/ - -.satus-shortcut { - justify-content: space-between; -} - -.satus-shortcut__value { - text-transform: uppercase; - font-size: 11px; - opacity: .5; -} - -.satus-shortcut__actions { - display: flex; - justify-content: flex-end; -} - -.satus-shortcut__actions .satus-button { - height: 32px; - background: rgba(0,0,0,.15); - margin: 8px 4px 0; - border-radius: 8px; -} - -.satus-shortcut__actions .satus-button:hover { - background: rgba(0,0,0,.25); -} - -.satus-shortcut__primary { - display: flex; - box-sizing: border-box; - width: 100%; - height: 68px; - padding: 16px; - background: rgba(0,0,0,.16); - align-items: center; -} - -.satus-shortcut__key { - display: flex; - box-sizing: border-box; - min-width: 32px; - height: 32px; - padding: 4px 8px; - border-radius: 4px; - background: #fff; - box-shadow: 0 1px 3px rgba(0, 0, 0, .15), inset 0 -3px 0 rgba(0, 0, 0, .1); - align-items: center; - justify-content: center; -} - -.satus-shortcut__plus { - position: relative; - width: 12px; - height: 12px; - margin: 8px; -} - -.satus-shortcut__plus::before { - position: absolute; - top: 0; - left: 5px; - width: 2px; - height: 12px; - content: ''; - background-color: #aaa; -} - -.satus-shortcut__plus::after { - position: absolute; - top: 5px; - left: 0; - width: 12px; - height: 2px; - content: ''; - background-color: #aaa; -} - -.satus-shortcut__mouse { - position: relative; - display: flex; - width: 28px; - height: 36px; - border-radius: 50%; - border-top-left-radius: 12px; - border-top-right-radius: 12px; - background: #fff; - box-shadow: 0 1px 3px rgba(0, 0, 0, .15), inset 0 -3px 0 rgba(0, 0, 0, .1); -} - -.satus-shortcut__mouse>div { - position: absolute; - top: 0; - left: 13px; - width: 2px; - height: 11px; - border-radius: 2px; - background: #ccc; -} - -.satus-shortcut__mouse::before { - position: absolute; - top: -4px; - left: 21px; - width: 2px; - height: 18px; - content: ''; - background: #f96754; -} - -.satus-shortcut__mouse.false::after { - position: absolute; - top: -12px; - left: 17px; - width: 0; - height: 0; - content: ''; - border-right: 5px solid transparent; - border-bottom: 8px solid #f96754; - border-left: 5px solid transparent; -} - -.satus-shortcut__mouse.true::after { - position: absolute; - top: 14px; - left: 17px; - width: 0; - height: 0; - content: ''; - border-top: 8px solid #f96754; - border-right: 5px solid transparent; - border-left: 5px solid transparent; -} - -.satus-section_shortcut { - width: 100%; - margin: 8px 0 0; - justify-content: flex-end; -} - -.satus-button_shortcut { - font-weight: 500; - overflow: hidden; - height: 28px; - min-height: 28px; - margin-right: 2px; - padding: 4px 8px; - text-transform: uppercase; - color: #f96754; - border-radius: 4px; -} -/*-------------------------------------------------------------- ->>> BASE ---------------------------------------------------------------*/ - -.satus-base{ - display: flex; - flex-direction: column; - width: 100%; - height: 100%; -} -/*-------------------------------------------------------------- ->>> TEXT FIELD ---------------------------------------------------------------*/ - -.satus-text-field { - position: relative; - padding: 0 16px; - background-color: #333347; - border-radius: 8px; - color: #c4c4d4; - overflow: hidden; - display: flex; -} - -.satus-text-field__pre { - display: flex; - position: relative; - height: 100%; - margin: 0; - padding: 0; - overflow: hidden; - align-items: center; - flex: 1; -} - -.satus-text-field__input { - font: inherit; - position: absolute; - top: 0; - left: 0; - width: 100%; - min-width: 0; - max-width: none; - height: 100%; - min-height: 0; - max-height: none; - margin: 0; - padding: 0; - opacity: 0; - border: none; - appearance: none; - z-index: 9; -} - -.satus-text-field__hidden-text { - position: absolute; - pointer-events: none; - opacity: 0; -} - -.satus-text-field__text { - position: absolute; - top: 0; - left: 0; - display: flex; - height: 100%; - margin: 0; - align-items: center; -} - -.satus-text-field__cursor { - position: absolute; - top: 6px; - left: 0; - display: none; - width: 2px; - height: 25px; - animation: blink 1s step-end 8; - background: #fa0; -} - -.satus-text-field__selection { - position: absolute; - top: 5px; - left: 0; - display: none; - width: 0; - height: 25px; - border: 1px solid rgba(255, 255, 255, .2); - border-radius: 3px; - background: rgba(255, 255, 255, .1); -} - -.satus-text-field__input:focus + * + * + * + .satus-text-field__cursor, -.satus-text-field__selection:not([disabled]) { - display: block; -} - -@keyframes blink { - from, - to { - opacity: 1; - } - 50% { - opacity: 0; - } -} - - -/*-------------------------------------------------------------- -# SYNTAX HIGHLIGHTING ---------------------------------------------------------------*/ - -.satus-text-field__text>.group { - color: #47ff47; - background-color: rgb(71, 255, 71, .16); -} - -.satus-text-field__text>.character-class { - color: #ffc247; - background-color: rgb(255, 170, 0, .16); -} - -.satus-text-field__text>.quantifier { - color: #47c2ff; - background-color: rgb(71, 194, 255, .16); -} - -.satus-text-field__text>.anchor { - color: #47c2ff; - background-color: rgb(71, 194, 255, .16); -} - -.satus-text-field__text>.metasequence { - color: #47ff47; - background-color: rgb(71, 255, 71, .16); -} - -.satus-text-field__text>.text { - color: #c4c4d4; - background-color: rgb(196, 196, 212, .16); -} -/*-------------------------------------------------------------- -# HEADER ---------------------------------------------------------------*/ - -.satus-header { - display: flex; - box-sizing: border-box; - height: 56px; - padding: 0 16px; - color: var(--satus-header-text); - background: var(--satus-header-background); - align-items: center; - justify-content: space-between; -} - -.satus-header .satus-h1--title { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - flex: 1; -} -/*-------------------------------------------------------------- ->>> ALERT ---------------------------------------------------------------*/ - -.satus-alert { - display: flex; - box-sizing: border-box; - min-height: 48px; - margin: 8px; - padding: 8px 16px; - border-radius: 8px; - align-items: center; -} - -.satus-alert--error { - color: #c55959; - border: 1px solid #641616; - background: #430f0f; -} -/*-------------------------------------------------------------- ->>> LAYERS ---------------------------------------------------------------*/ - -.satus-layers { - position: relative; - overflow: hidden; - color: var(--satus-layers-text); - background: var(--satus-layers-background); - flex: 1; -} - -.satus-layer { - position: absolute; - top: 0; - left: 0; - display: flex; - overflow-y: auto; - width: 100%; - height: 100%; - flex-wrap: wrap; - align-content: flex-start; -} -/*-------------------------------------------------------------- -# INPUT ---------------------------------------------------------------*/ - -.satus-input[type=text] { - font: inherit; - box-sizing: border-box; - width: 100%; - margin: 0; - padding: 0; - padding: 0 8px; - color: inherit; - border: none; - outline: none; - background: none; - appearance: none; -} -/**/ - -.satus-aside { - color: var(--satus-aside-text); - background: var(--satus-aside-background); - box-sizing: border-box; -} -/*-------------------------------------------------------------- ->>> SELECT ---------------------------------------------------------------*/ - -.satus-select { - position: relative; - display: flex; - box-sizing: border-box; - align-items: center; - justify-content: space-between; -} - -.satus-select__value { - margin-left: 16px; - text-align: right; - opacity: .75; -} - -.satus-select select { - font: inherit; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - margin: 0; - padding: 0; - padding: inherit; - cursor: pointer; - opacity: 0; - color: inherit; - border: none; - outline: none; - background: none; - appearance: none; -} - -.satus-select:hover { - cursor: pointer; - background-color: var(--satus-hover); -} -/*-------------------------------------------------------------- ->>> PLUVIAM ---------------------------------------------------------------*/ - -.satus-pluviam { - position: absolute; - transform: scale(0); - animation-name: pluviam; - animation-duration: 1000ms; - opacity: var(--satus-pluviam-opacity, .08); - border-radius: 50%; - background: var(--satus-pluviam-background, #000); - animation-fill-mode: forwards; -} - -@keyframes pluviam { - 0% { - transform: scale(0); - opacity: var(--satus-pluviam-opacity, .08); - } - 70% { - transform: scale(.8); - opacity: var(--satus-pluviam-opacity, .08); - } - 100% { - transform: scale(1); - opacity: 0; - } -} \ No newline at end of file diff --git a/satus.js b/satus.js deleted file mode 100644 index 67b97b5..0000000 --- a/satus.js +++ /dev/null @@ -1,2074 +0,0 @@ - -/*-------------------------------------------------------------- ->>> CORE: ----------------------------------------------------------------- -# Global variable -# Functions -# Render ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# GLOBAL VARIABLE ---------------------------------------------------------------*/ - -var satus = { - components: {}, - events: {}, - locale: { - strings: {} - }, - storage: { - attributes: {}, - data: {} - } -}; - - -/*-------------------------------------------------------------- -# FUNCTIONS ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# APPEND ---------------------------------------------------------------*/ - -satus.append = function (element, container) { - (container || document.body).appendChild(element); -}; - - -/*-------------------------------------------------------------- -# ANIMATION DURATION ---------------------------------------------------------------*/ - -satus.getAnimationDuration = function (element) { - return Number(window.getComputedStyle(element).getPropertyValue('animation-duration').replace(/[^0-9.]/g, '')) * 1000; -}; - - -/*-------------------------------------------------------------- -# APPEND ---------------------------------------------------------------*/ - -satus.attr = function (element, attributes) { - if (attributes) { - for (var key in attributes) { - if (element.is_svg) { - element.setAttributeNS(null, key, attributes[key]); - } else { - var value = attributes[key]; - - if (['placeholder', 'title'].indexOf(key) !== -1) { - value = satus.locale.get(value); - } - - element.setAttribute(key, value); - } - } - } -}; - -satus.elementIndex = function (element) { - return Array.prototype.slice.call(element.parentNode.children).indexOf(element); -}; - - -/*-------------------------------------------------------------- -# DATA ---------------------------------------------------------------*/ - -satus.data = function (element, data) { - if (data) { - for (var key in data) { - element.dataset[key] = data[key]; - } - } -}; - - -/*-------------------------------------------------------------- -# PROPERTIES ---------------------------------------------------------------*/ - -satus.properties = function (element, properties) { - if (properties) { - for (var key in properties) { - element[key] = properties[key]; - } - } -}; - - -/*-------------------------------------------------------------- -# CAMELIZE ---------------------------------------------------------------*/ - -satus.camelize = function (string) { - var result = ''; - - for (var i = 0, l = string.length; i < l; i++) { - var character = string[i]; - - if (character === '-') { - i++; - - result += string[i].toUpperCase(); - } else { - result += character; - } - } - - return result; -}; - - -/*-------------------------------------------------------------- -# SNAKELIZE ---------------------------------------------------------------*/ - -satus.snakelize = function (string) { - return string.replace(/([A-Z])/g, '-$1').toLowerCase(); -}; - - -/*-------------------------------------------------------------- -# CLASS ---------------------------------------------------------------*/ - -satus.class = function (element, string) { - if (string) { - element.className += ' ' + string; - } -}; - - -/*-------------------------------------------------------------- -# EMPTY ---------------------------------------------------------------*/ - -satus.empty = function (element) { - for (var i = element.childNodes.length - 1; i > -1; i--) { - element.childNodes[i].remove(); - } -}; - - -/*-------------------------------------------------------------- -# EVENTS ---------------------------------------------------------------*/ - -Object.defineProperty(satus.events, 'add', { - value: function (type, listener) { - if (this.hasOwnProperty(type) === false) { - this[type] = []; - } - - this[type].push(listener); - } -}); - - -/*-------------------------------------------------------------- -# ISSET ---------------------------------------------------------------*/ - -satus.isset = function (variable) { - if (variable === null || variable === undefined) { - return false; - } - - return true; -}; - - -/*-------------------------------------------------------------- -# FETCH ---------------------------------------------------------------*/ - -satus.fetch = function (url, success, error) { - fetch(url).then(function (response) { - if (response.ok) { - response.json().then(success); - } else { - error(); - } - }); -}; - - -/*-------------------------------------------------------------- -# AJAX ---------------------------------------------------------------*/ - -satus.ajax = function (url, success, error) { - var xhr = new XMLHttpRequest(); - - xhr.onload = function () { - success(this.response); - }; - xhr.onerror = function () { - error(success); - }; - - xhr.open('GET', url, true); - xhr.send(); -}; - - -/*-------------------------------------------------------------- -# STORAGE ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# GET ---------------------------------------------------------------*/ - -satus.storage.get = function (name) { - var target = satus.storage.data; - - if (satus.isset(name) === false) { - return; - } - - name = name.split('/').filter(function (value) { - return value != ''; - }); - - for (var i = 0, l = name.length; i < l; i++) { - if (satus.isset(target[name[i]])) { - target = target[name[i]]; - } else { - return undefined; - } - } - - return target; -}; - - -/*-------------------------------------------------------------- -# SET ---------------------------------------------------------------*/ - -satus.storage.set = function (name, value) { - var items = {}, - target = satus.storage.data; - - if (satus.isset(name) === false) { - return; - } - - name = name.split('/').filter(function (value) { - return value != ''; - }); - - for (var i = 0, l = name.length; i < l; i++) { - var item = name[i]; - - if (i < l - 1) { - - if (target[item]) { - target = target[item]; - } else { - target[item] = {}; - - target = target[item]; - } - } else { - target[item] = value; - } - } - - for (var key in this.data) { - if (typeof this.data[key] !== 'function') { - items[key] = this.data[key]; - } - } - - if (satus.storage.attributes[name]) { - document.body.setAttribute(name, value); - } - - chrome.storage.local.set(items); -}; - - -/*-------------------------------------------------------------- -# IMPORT ---------------------------------------------------------------*/ - -satus.storage.import = function (callback) { - chrome.storage.local.get(function (items) { - for (var key in items) { - if (satus.storage.attributes[key]) { - document.body.setAttribute(key, items[key]); - } - - satus.storage.data[key] = items[key]; - } - - if (callback) { - callback(items); - } - }); -}; - - -/*-------------------------------------------------------------- -# CLEAR ---------------------------------------------------------------*/ - -satus.storage.clear = function (callback) { - chrome.storage.local.clear(callback); -}; - - -/*-------------------------------------------------------------- -# LOCALIZATION ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# GET ---------------------------------------------------------------*/ - -satus.locale.get = function (string) { - return this.strings[string] || string; -}; - - -/*-------------------------------------------------------------- -# ON ---------------------------------------------------------------*/ - -satus.on = function (element, events) { - if (this.isset(events) && typeof events === 'object') { - for (var selector in events) { - var type = typeof events[selector]; - - if (type === 'function') { - element.addEventListener(selector, events[selector]); - } else if (type === 'object') { - element.addEventListener(selector, function (event) { - this.skeleton.on[event.type].parent = this.skeleton; - - if (this.skeleton.on[event.type].component !== 'modal' && this.base && this.base.layers) { - this.base.layers.open(this.skeleton.on[event.type]); - } else { - satus.render(this.skeleton.on[event.type], this.base); - } - }); - } else if (type === 'string') { - element.addEventListener(selector, function () { - var match = this.skeleton.on[event.type].match(/(["'`].+["'`]|[^.()]+)/g), - target = this.base; - - for (var i = 0, l = match.length; i < l; i++) { - var key = match[i]; - - if (target.skeleton[key]) { - target = target.skeleton[key]; - } else { - if (typeof target[key] === 'function') { - target[key](); - } else { - target = target[key]; - } - } - - if (target.rendered) { - target = target.rendered; - } - } - }); - } - } - } -}; - - -/*-------------------------------------------------------------- -# STYLE ---------------------------------------------------------------*/ - -satus.style = function (component, object) { - for (var key in object) { - component.style[key] = object[key]; - } -}; - - -/*-------------------------------------------------------------- -# SEARCH ---------------------------------------------------------------*/ - -satus.search = function (query, object, callback, categories) { - var threads = 0, - folder = '', - results = {}; - - query = query.toLowerCase(); - - function parse(items) { - threads++; - - for (var key in items) { - if (key !== 'rendered' && key !== 'base' && key !== 'parent') { - var item = items[key]; - - if (['switch', 'select', 'slider', 'shortcut'].indexOf(item.component) !== -1 && key.indexOf(query) !== -1) { - if (categories === true) { - if (!results[folder]) { - results[folder] = {}; - } - - results[folder][key] = item; - } else { - results[key] = item; - } - } - - if (typeof item === 'object') { - parse(item); - } - } - } - - threads--; - - if (threads === 0) { - callback(results); - } - } - - parse(object); -}; - - -/*-------------------------------------------------------------- -# TEXT ---------------------------------------------------------------*/ - -satus.text = function (component, string) { - if (string) { - component.appendChild(document.createTextNode(this.locale.get(string))); - } -}; - - -/*-------------------------------------------------------------- -# RENDER ---------------------------------------------------------------*/ - -satus.render = function (skeleton, container, skip, property) { - if (skeleton.hasOwnProperty('component') && skip !== true) { - var component, - name = skeleton.component, - camelized_name = this.camelize(name); - - if (skeleton.on && skeleton.on.beforerender) { - skeleton.on.beforerender(skeleton); - } - - if (this.components[camelized_name]) { - component = this.components[camelized_name](skeleton); - - if (this.isset(component.inner) === false) { - component.inner = component; - } - } else if (name === 'svg' || container && container.is_svg) { - component = document.createElementNS('http://www.w3.org/2000/svg', name); - - component.is_svg = true; - - component.inner = component; - } else { - component = document.createElement(skeleton.component); - - component.inner = component; - } - - if (component.inner.hasOwnProperty('base') === false && container) { - component.inner.base = container.base; - } - - if (component.inner.base && name === 'layers') { - component.inner.base.layers = component; - } - - skeleton.rendered = component; - component.skeleton = skeleton; - - if (skeleton.hasOwnProperty('storage')) { - component.storage = skeleton.storage; - } else if (property) { - component.storage = property; - } - - component.className = (component.className + ' satus-' + skeleton.component).trim(); - - component.change = function (value) { - satus.storage.set(this.storage, value); - }; - - if (skeleton.variant) { - component.className += ' satus-' + skeleton.component + '--' + skeleton.variant; - } - - this.append(component, container); - - container = component.inner || component; - - this.class(component, skeleton.class); - this.style(component, skeleton.style); - this.attr(component, skeleton.attr); - this.data(component, skeleton.data); - this.properties(component, skeleton.properties); - this.on(component, skeleton.on); - this.text(container, skeleton.text); - - component.dispatchEvent(new CustomEvent('render')); - - if (this.events.hasOwnProperty('render')) { - for (var i = 0, l = this.events['render'].length; i < l; i++) { - this.events['render'][i](component, skeleton); - } - } - } - - if (!component || component.render_children !== false) { - for (var key in skeleton) { - if (key !== 'parent' && skeleton[key] && skeleton[key].hasOwnProperty('component')) { - skeleton[key].parent = skeleton; - - this.render(skeleton[key], container, false, key); - } - } - } -}; -/*-------------------------------------------------------------- ->>> COLOR PICKER ---------------------------------------------------------------*/ - -satus.components.colorPicker = function (skeleton) { - var component = document.createElement('button'), - component_value = document.createElement('span'); - - component.className = 'satus-button'; - component_value.className = 'satus-color-picker__value'; - - component.valueElement = component_value; - - component.addEventListener('render', function () { - var data = satus.storage.get(this.storage) || this.skeleton.value || { - rgb: [0, 0, 0] - }; - - this.valueElement.style.backgroundColor = 'rgb(' + data.rgb[0] + ',' + data.rgb[1] + ',' + data.rgb[2] + ')'; - }); - - component.addEventListener('click', function () { - satus.render({ - component: 'modal', - class: 'satus-modal--color-picker', - properties: { - parentComponent: this - }, - - canvas: { - component: 'canvas', - on: { - render: function () { - var data = satus.storage.get(this.parentNode.parentNode.parentComponent.storage) || this.parentNode.parentNode.parentComponent.skeleton.value || { - rgb: [0, 0, 0] - }, - ctx = this.getContext('2d'), - image = new Image(); - - this.parentNode.data = data; - - image.addEventListener('load', function () { - ctx.drawImage(this, 0, 0); - }); - - image.src = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNzAgMjcwIj48ZGVmcz48cmFkaWFsR3JhZGllbnQgaWQ9ImEiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiNmZmYiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmYiIHN0b3Atb3BhY2l0eT0iMCIvPjwvcmFkaWFsR3JhZGllbnQ+PC9kZWZzPjxnIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMTMzIiBjbGFzcz0iSXJvV2hlZWxIdWUiPjxwYXRoIHN0cm9rZT0iaHNsKDI0MCwgMTAwJSwgNTAlKSIgZD0iTTIwMS40NzcgMTM2Ljc0YTY2LjUgNjYuNSAwIDAwLjAyMy0xLjc0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjQxLCAxMDAlLCA1MCUpIiBkPSJNMjAxLjQzNyAxMzcuOWE2Ni41IDY2LjUgMCAwMC4wNTMtMS43NCIvPjxwYXRoIHN0cm9rZT0iaHNsKDI0MiwgMTAwJSwgNTAlKSIgZD0iTTIwMS4zNzYgMTM5LjA2YTY2LjUgNjYuNSAwIDAwLjA4My0xLjc0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjQzLCAxMDAlLCA1MCUpIiBkPSJNMjAxLjI5NSAxNDAuMjE4YTY2LjUgNjYuNSAwIDAwLjExNC0xLjczOCIvPjxwYXRoIHN0cm9rZT0iaHNsKDI0NCwgMTAwJSwgNTAlKSIgZD0iTTIwMS4xOTQgMTQxLjM3NGE2Ni41IDY2LjUgMCAwMC4xNDQtMS43MzUiLz48cGF0aCBzdHJva2U9ImhzbCgyNDUsIDEwMCUsIDUwJSkiIGQ9Ik0yMDEuMDczIDE0Mi41MjhhNjYuNSA2Ni41IDAgMDAuMTc0LTEuNzMyIi8+PHBhdGggc3Ryb2tlPSJoc2woMjQ2LCAxMDAlLCA1MCUpIiBkPSJNMjAwLjkzMSAxNDMuNjhhNjYuNSA2Ni41IDAgMDAuMjA1LTEuNzI5Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjQ3LCAxMDAlLCA1MCUpIiBkPSJNMjAwLjc3IDE0NC44M2E2Ni41IDY2LjUgMCAwMC4yMzQtMS43MjYiLz48cGF0aCBzdHJva2U9ImhzbCgyNDgsIDEwMCUsIDUwJSkiIGQ9Ik0yMDAuNTg4IDE0NS45NzZhNjYuNSA2Ni41IDAgMDAuMjY1LTEuNzIxIi8+PHBhdGggc3Ryb2tlPSJoc2woMjQ5LCAxMDAlLCA1MCUpIiBkPSJNMjAwLjM4NiAxNDcuMTE5YTY2LjUgNjYuNSAwIDAwLjI5NS0xLjcxNiIvPjxwYXRoIHN0cm9rZT0iaHNsKDI1MCwgMTAwJSwgNTAlKSIgZD0iTTIwMC4xNjUgMTQ4LjI1OGE2Ni41IDY2LjUgMCAwMC4zMjUtMS43MSIvPjxwYXRoIHN0cm9rZT0iaHNsKDI1MSwgMTAwJSwgNTAlKSIgZD0iTTE5OS45MjQgMTQ5LjM5M2E2Ni41IDY2LjUgMCAwMC4zNTQtMS43MDQiLz48cGF0aCBzdHJva2U9ImhzbCgyNTIsIDEwMCUsIDUwJSkiIGQ9Ik0xOTkuNjYzIDE1MC41MjRhNjYuNSA2Ni41IDAgMDAuMzg0LTEuNjk4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjUzLCAxMDAlLCA1MCUpIiBkPSJNMTk5LjM4MiAxNTEuNjVhNjYuNSA2Ni41IDAgMDAuNDE0LTEuNjkiLz48cGF0aCBzdHJva2U9ImhzbCgyNTQsIDEwMCUsIDUwJSkiIGQ9Ik0xOTkuMDgxIDE1Mi43NzFhNjYuNSA2Ni41IDAgMDAuNDQ0LTEuNjgzIi8+PHBhdGggc3Ryb2tlPSJoc2woMjU1LCAxMDAlLCA1MCUpIiBkPSJNMTk4Ljc2MiAxNTMuODg3YTY2LjUgNjYuNSAwIDAwLjQ3Mi0xLjY3NiIvPjxwYXRoIHN0cm9rZT0iaHNsKDI1NiwgMTAwJSwgNTAlKSIgZD0iTTE5OC40MjIgMTU0Ljk5N2E2Ni41IDY2LjUgMCAwMC41MDItMS42NjciLz48cGF0aCBzdHJva2U9ImhzbCgyNTcsIDEwMCUsIDUwJSkiIGQ9Ik0xOTguMDY0IDE1Ni4xYTY2LjUgNjYuNSAwIDAwLjUzLTEuNjU3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjU4LCAxMDAlLCA1MCUpIiBkPSJNMTk3LjY4NiAxNTcuMTk4YTY2LjUgNjYuNSAwIDAwLjU2LTEuNjQ4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjU5LCAxMDAlLCA1MCUpIiBkPSJNMTk3LjI4OSAxNTguMjg5YTY2LjUgNjYuNSAwIDAwLjU4OC0xLjYzOSIvPjxwYXRoIHN0cm9rZT0iaHNsKDI2MCwgMTAwJSwgNTAlKSIgZD0iTTE5Ni44NzMgMTU5LjM3MmE2Ni41IDY2LjUgMCAwMC42MTctMS42MjgiLz48cGF0aCBzdHJva2U9ImhzbCgyNjEsIDEwMCUsIDUwJSkiIGQ9Ik0xOTYuNDM4IDE2MC40NDhhNjYuNSA2Ni41IDAgMDAuNjQ1LTEuNjE3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjYyLCAxMDAlLCA1MCUpIiBkPSJNMTk1Ljk4NCAxNjEuNTE3YTY2LjUgNjYuNSAwIDAwLjY3NC0xLjYwNiIvPjxwYXRoIHN0cm9rZT0iaHNsKDI2MywgMTAwJSwgNTAlKSIgZD0iTTE5NS41MTIgMTYyLjU3N2E2Ni41IDY2LjUgMCAwMC43MDItMS41OTMiLz48cGF0aCBzdHJva2U9ImhzbCgyNjQsIDEwMCUsIDUwJSkiIGQ9Ik0xOTUuMDIyIDE2My42MjlhNjYuNSA2Ni41IDAgMDAuNzI5LTEuNTgxIi8+PHBhdGggc3Ryb2tlPSJoc2woMjY1LCAxMDAlLCA1MCUpIiBkPSJNMTk0LjUxMyAxNjQuNjcyYTY2LjUgNjYuNSAwIDAwLjc1Ni0xLjU2OCIvPjxwYXRoIHN0cm9rZT0iaHNsKDI2NiwgMTAwJSwgNTAlKSIgZD0iTTE5My45ODYgMTY1LjcwNmE2Ni41IDY2LjUgMCAwMC43ODQtMS41NTQiLz48cGF0aCBzdHJva2U9ImhzbCgyNjcsIDEwMCUsIDUwJSkiIGQ9Ik0xOTMuNDQxIDE2Ni43MzFhNjYuNSA2Ni41IDAgMDAuODEtMS41NCIvPjxwYXRoIHN0cm9rZT0iaHNsKDI2OCwgMTAwJSwgNTAlKSIgZD0iTTE5Mi44NzkgMTY3Ljc0NmE2Ni41IDY2LjUgMCAwMC44MzctMS41MjYiLz48cGF0aCBzdHJva2U9ImhzbCgyNjksIDEwMCUsIDUwJSkiIGQ9Ik0xOTIuMjk4IDE2OC43NTFhNjYuNSA2Ni41IDAgMDAuODY0LTEuNTExIi8+PHBhdGggc3Ryb2tlPSJoc2woMjcwLCAxMDAlLCA1MCUpIiBkPSJNMTkxLjcgMTY5Ljc0NmE2Ni41IDY2LjUgMCAwMC44OS0xLjQ5NiIvPjxwYXRoIHN0cm9rZT0iaHNsKDI3MSwgMTAwJSwgNTAlKSIgZD0iTTE5MS4wODYgMTcwLjczYTY2LjUgNjYuNSAwIDAwLjkxNi0xLjQ4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjcyLCAxMDAlLCA1MCUpIiBkPSJNMTkwLjQ1MyAxNzEuNzA0YTY2LjUgNjYuNSAwIDAwLjk0Mi0xLjQ2NCIvPjxwYXRoIHN0cm9rZT0iaHNsKDI3MywgMTAwJSwgNTAlKSIgZD0iTTE4OS44MDQgMTcyLjY2NmE2Ni41IDY2LjUgMCAwMC45NjgtMS40NDgiLz48cGF0aCBzdHJva2U9ImhzbCgyNzQsIDEwMCUsIDUwJSkiIGQ9Ik0xODkuMTM5IDE3My42MTdhNjYuNSA2Ni41IDAgMDAuOTkyLTEuNDMiLz48cGF0aCBzdHJva2U9ImhzbCgyNzUsIDEwMCUsIDUwJSkiIGQ9Ik0xODguNDU2IDE3NC41NTZhNjYuNSA2Ni41IDAgMDAxLjAxOC0xLjQxMyIvPjxwYXRoIHN0cm9rZT0iaHNsKDI3NiwgMTAwJSwgNTAlKSIgZD0iTTE4Ny43NTggMTc1LjQ4M2E2Ni41IDY2LjUgMCAwMDEuMDQyLTEuMzk1Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjc3LCAxMDAlLCA1MCUpIiBkPSJNMTg3LjA0MyAxNzYuMzk3YTY2LjUgNjYuNSAwIDAwMS4wNjYtMS4zNzYiLz48cGF0aCBzdHJva2U9ImhzbCgyNzgsIDEwMCUsIDUwJSkiIGQ9Ik0xODYuMzEzIDE3Ny4zYTY2LjUgNjYuNSAwIDAwMS4wOS0xLjM1OSIvPjxwYXRoIHN0cm9rZT0iaHNsKDI3OSwgMTAwJSwgNTAlKSIgZD0iTTE4NS41NjcgMTc4LjE4OGE2Ni41IDY2LjUgMCAwMDEuMTEzLTEuMzM4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjgwLCAxMDAlLCA1MCUpIiBkPSJNMTg0LjgwNiAxNzkuMDY0YTY2LjUgNjYuNSAwIDAwMS4xMzYtMS4zMTkiLz48cGF0aCBzdHJva2U9ImhzbCgyODEsIDEwMCUsIDUwJSkiIGQ9Ik0xODQuMDI5IDE3OS45MjdhNjYuNSA2Ni41IDAgMDAxLjE2LTEuMyIvPjxwYXRoIHN0cm9rZT0iaHNsKDI4MiwgMTAwJSwgNTAlKSIgZD0iTTE4My4yMzcgMTgwLjc3NmE2Ni41IDY2LjUgMCAwMDEuMTgyLTEuMjc5Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjgzLCAxMDAlLCA1MCUpIiBkPSJNMTgyLjQzMSAxODEuNjFhNjYuNSA2Ni41IDAgMDAxLjIwNC0xLjI1NyIvPjxwYXRoIHN0cm9rZT0iaHNsKDI4NCwgMTAwJSwgNTAlKSIgZD0iTTE4MS42MSAxODIuNDMxYTY2LjUgNjYuNSAwIDAwMS4yMjYtMS4yMzYiLz48cGF0aCBzdHJva2U9ImhzbCgyODUsIDEwMCUsIDUwJSkiIGQ9Ik0xODAuNzc2IDE4My4yMzdhNjYuNSA2Ni41IDAgMDAxLjI0Ny0xLjIxNCIvPjxwYXRoIHN0cm9rZT0iaHNsKDI4NiwgMTAwJSwgNTAlKSIgZD0iTTE3OS45MjcgMTg0LjAyOWE2Ni41IDY2LjUgMCAwMDEuMjY4LTEuMTkzIi8+PHBhdGggc3Ryb2tlPSJoc2woMjg3LCAxMDAlLCA1MCUpIiBkPSJNMTc5LjA2NCAxODQuODA2YTY2LjUgNjYuNSAwIDAwMS4yODktMS4xNzEiLz48cGF0aCBzdHJva2U9ImhzbCgyODgsIDEwMCUsIDUwJSkiIGQ9Ik0xNzguMTg4IDE4NS41NjdhNjYuNSA2Ni41IDAgMDAxLjMxLTEuMTQ4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjg5LCAxMDAlLCA1MCUpIiBkPSJNMTc3LjMgMTg2LjMxM2E2Ni41IDY2LjUgMCAwMDEuMzI4LTEuMTI1Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjkwLCAxMDAlLCA1MCUpIiBkPSJNMTc2LjM5NyAxODcuMDQzYTY2LjUgNjYuNSAwIDAwMS4zNDgtMS4xMDEiLz48cGF0aCBzdHJva2U9ImhzbCgyOTEsIDEwMCUsIDUwJSkiIGQ9Ik0xNzUuNDgzIDE4Ny43NThhNjYuNSA2Ni41IDAgMDAxLjM2Ny0xLjA3OCIvPjxwYXRoIHN0cm9rZT0iaHNsKDI5MiwgMTAwJSwgNTAlKSIgZD0iTTE3NC41NTYgMTg4LjQ1NmE2Ni41IDY2LjUgMCAwMDEuMzg1LTEuMDUzIi8+PHBhdGggc3Ryb2tlPSJoc2woMjkzLCAxMDAlLCA1MCUpIiBkPSJNMTczLjYxNyAxODkuMTM5YTY2LjUgNjYuNSAwIDAwMS40MDQtMS4wMyIvPjxwYXRoIHN0cm9rZT0iaHNsKDI5NCwgMTAwJSwgNTAlKSIgZD0iTTE3Mi42NjYgMTg5LjgwNGE2Ni41IDY2LjUgMCAwMDEuNDIyLTEuMDA0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjk1LCAxMDAlLCA1MCUpIiBkPSJNMTcxLjcwNCAxOTAuNDUzYTY2LjUgNjYuNSAwIDAwMS40MzktLjk4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjk2LCAxMDAlLCA1MCUpIiBkPSJNMTcwLjczIDE5MS4wODZhNjYuNSA2Ni41IDAgMDAxLjQ1Ni0uOTU1Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjk3LCAxMDAlLCA1MCUpIiBkPSJNMTY5Ljc0NiAxOTEuN2E2Ni41IDY2LjUgMCAwMDEuNDcyLS45MjgiLz48cGF0aCBzdHJva2U9ImhzbCgyOTgsIDEwMCUsIDUwJSkiIGQ9Ik0xNjguNzUxIDE5Mi4yOThhNjYuNSA2Ni41IDAgMDAxLjQ4OS0uOTAzIi8+PHBhdGggc3Ryb2tlPSJoc2woMjk5LCAxMDAlLCA1MCUpIiBkPSJNMTY3Ljc0NiAxOTIuODc5YTY2LjUgNjYuNSAwIDAwMS41MDQtLjg3NyIvPjxwYXRoIHN0cm9rZT0iaHNsKDMwMCwgMTAwJSwgNTAlKSIgZD0iTTE2Ni43MzEgMTkzLjQ0MWE2Ni41IDY2LjUgMCAwMDEuNTE5LS44NSIvPjxwYXRoIHN0cm9rZT0iaHNsKDMwMSwgMTAwJSwgNTAlKSIgZD0iTTE2NS43MDYgMTkzLjk4NmE2Ni41IDY2LjUgMCAwMDEuNTM0LS44MjQiLz48cGF0aCBzdHJva2U9ImhzbCgzMDIsIDEwMCUsIDUwJSkiIGQ9Ik0xNjQuNjcyIDE5NC41MTNhNjYuNSA2Ni41IDAgMDAxLjU0OC0uNzk3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzAzLCAxMDAlLCA1MCUpIiBkPSJNMTYzLjYyOSAxOTUuMDIyYTY2LjUgNjYuNSAwIDAwMS41NjEtLjc3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzA0LCAxMDAlLCA1MCUpIiBkPSJNMTYyLjU3NyAxOTUuNTEyYTY2LjUgNjYuNSAwIDAwMS41NzUtLjc0MiIvPjxwYXRoIHN0cm9rZT0iaHNsKDMwNSwgMTAwJSwgNTAlKSIgZD0iTTE2MS41MTcgMTk1Ljk4NGE2Ni41IDY2LjUgMCAwMDEuNTg3LS43MTUiLz48cGF0aCBzdHJva2U9ImhzbCgzMDYsIDEwMCUsIDUwJSkiIGQ9Ik0xNjAuNDQ4IDE5Ni40MzhhNjYuNSA2Ni41IDAgMDAxLjYtLjY4NyIvPjxwYXRoIHN0cm9rZT0iaHNsKDMwNywgMTAwJSwgNTAlKSIgZD0iTTE1OS4zNzIgMTk2Ljg3M2E2Ni41IDY2LjUgMCAwMDEuNjEyLS42NiIvPjxwYXRoIHN0cm9rZT0iaHNsKDMwOCwgMTAwJSwgNTAlKSIgZD0iTTE1OC4yODkgMTk3LjI4OWE2Ni41IDY2LjUgMCAwMDEuNjIyLS42MzEiLz48cGF0aCBzdHJva2U9ImhzbCgzMDksIDEwMCUsIDUwJSkiIGQ9Ik0xNTcuMTk4IDE5Ny42ODZhNjYuNSA2Ni41IDAgMDAxLjYzMy0uNjAzIi8+PHBhdGggc3Ryb2tlPSJoc2woMzEwLCAxMDAlLCA1MCUpIiBkPSJNMTU2LjEgMTk4LjA2NGE2Ni41IDY2LjUgMCAwMDEuNjQ0LS41NzQiLz48cGF0aCBzdHJva2U9ImhzbCgzMTEsIDEwMCUsIDUwJSkiIGQ9Ik0xNTQuOTk3IDE5OC40MjJhNjYuNSA2Ni41IDAgMDAxLjY1My0uNTQ1Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzEyLCAxMDAlLCA1MCUpIiBkPSJNMTUzLjg4NyAxOTguNzYyYTY2LjUgNjYuNSAwIDAwMS42NjMtLjUxNyIvPjxwYXRoIHN0cm9rZT0iaHNsKDMxMywgMTAwJSwgNTAlKSIgZD0iTTE1Mi43NzEgMTk5LjA4MWE2Ni41IDY2LjUgMCAwMDEuNjcyLS40ODciLz48cGF0aCBzdHJva2U9ImhzbCgzMTQsIDEwMCUsIDUwJSkiIGQ9Ik0xNTEuNjUgMTk5LjM4MmE2Ni41IDY2LjUgMCAwMDEuNjgtLjQ1OCIvPjxwYXRoIHN0cm9rZT0iaHNsKDMxNSwgMTAwJSwgNTAlKSIgZD0iTTE1MC41MjQgMTk5LjY2M2E2Ni41IDY2LjUgMCAwMDEuNjg3LS40MjkiLz48cGF0aCBzdHJva2U9ImhzbCgzMTYsIDEwMCUsIDUwJSkiIGQ9Ik0xNDkuMzkzIDE5OS45MjRhNjYuNSA2Ni41IDAgMDAxLjY5NS0uNCIvPjxwYXRoIHN0cm9rZT0iaHNsKDMxNywgMTAwJSwgNTAlKSIgZD0iTTE0OC4yNTggMjAwLjE2NWE2Ni41IDY2LjUgMCAwMDEuNzAxLS4zNyIvPjxwYXRoIHN0cm9rZT0iaHNsKDMxOCwgMTAwJSwgNTAlKSIgZD0iTTE0Ny4xMTkgMjAwLjM4NmE2Ni41IDY2LjUgMCAwMDEuNzA3LS4zNCIvPjxwYXRoIHN0cm9rZT0iaHNsKDMxOSwgMTAwJSwgNTAlKSIgZD0iTTE0NS45NzYgMjAwLjU4OGE2Ni41IDY2LjUgMCAwMDEuNzEzLS4zMSIvPjxwYXRoIHN0cm9rZT0iaHNsKDMyMCwgMTAwJSwgNTAlKSIgZD0iTTE0NC44MyAyMDAuNzdhNjYuNSA2Ni41IDAgMDAxLjcxOC0uMjgiLz48cGF0aCBzdHJva2U9ImhzbCgzMjEsIDEwMCUsIDUwJSkiIGQ9Ik0xNDMuNjggMjAwLjkzMWE2Ni41IDY2LjUgMCAwMDEuNzIzLS4yNSIvPjxwYXRoIHN0cm9rZT0iaHNsKDMyMiwgMTAwJSwgNTAlKSIgZD0iTTE0Mi41MjggMjAxLjA3M2E2Ni41IDY2LjUgMCAwMDEuNzI3LS4yMiIvPjxwYXRoIHN0cm9rZT0iaHNsKDMyMywgMTAwJSwgNTAlKSIgZD0iTTE0MS4zNzQgMjAxLjE5NGE2Ni41IDY2LjUgMCAwMDEuNzMtLjE5Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzI0LCAxMDAlLCA1MCUpIiBkPSJNMTQwLjIxOCAyMDEuMjk1YTY2LjUgNjYuNSAwIDAwMS43MzMtLjE2Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzI1LCAxMDAlLCA1MCUpIiBkPSJNMTM5LjA2IDIwMS4zNzZhNjYuNSA2Ni41IDAgMDAxLjczNi0uMTMiLz48cGF0aCBzdHJva2U9ImhzbCgzMjYsIDEwMCUsIDUwJSkiIGQ9Ik0xMzcuOSAyMDEuNDM3YTY2LjUgNjYuNSAwIDAwMS43MzktLjA5OSIvPjxwYXRoIHN0cm9rZT0iaHNsKDMyNywgMTAwJSwgNTAlKSIgZD0iTTEzNi43NCAyMDEuNDc3YTY2LjUgNjYuNSAwIDAwMS43NC0uMDY4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzI4LCAxMDAlLCA1MCUpIiBkPSJNMTM1LjU4IDIwMS40OTdhNjYuNSA2Ni41IDAgMDAxLjc0LS4wMzgiLz48cGF0aCBzdHJva2U9ImhzbCgzMjksIDEwMCUsIDUwJSkiIGQ9Ik0xMzQuNDIgMjAxLjQ5N2E2Ni41IDY2LjUgMCAwMDEuNzQtLjAwNyIvPjxwYXRoIHN0cm9rZT0iaHNsKDMzMCwgMTAwJSwgNTAlKSIgZD0iTTEzMy4yNiAyMDEuNDc3YTY2LjUgNjYuNSAwIDAwMS43NC4wMjMiLz48cGF0aCBzdHJva2U9ImhzbCgzMzEsIDEwMCUsIDUwJSkiIGQ9Ik0xMzIuMSAyMDEuNDM3YTY2LjUgNjYuNSAwIDAwMS43NC4wNTMiLz48cGF0aCBzdHJva2U9ImhzbCgzMzIsIDEwMCUsIDUwJSkiIGQ9Ik0xMzAuOTQgMjAxLjM3NmE2Ni41IDY2LjUgMCAwMDEuNzQuMDgzIi8+PHBhdGggc3Ryb2tlPSJoc2woMzMzLCAxMDAlLCA1MCUpIiBkPSJNMTI5Ljc4MiAyMDEuMjk1YTY2LjUgNjYuNSAwIDAwMS43MzguMTE0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzM0LCAxMDAlLCA1MCUpIiBkPSJNMTI4LjYyNiAyMDEuMTk0YTY2LjUgNjYuNSAwIDAwMS43MzUuMTQ0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzM1LCAxMDAlLCA1MCUpIiBkPSJNMTI3LjQ3MiAyMDEuMDczYTY2LjUgNjYuNSAwIDAwMS43MzIuMTc0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzM2LCAxMDAlLCA1MCUpIiBkPSJNMTI2LjMyIDIwMC45MzFhNjYuNSA2Ni41IDAgMDAxLjcyOS4yMDUiLz48cGF0aCBzdHJva2U9ImhzbCgzMzcsIDEwMCUsIDUwJSkiIGQ9Ik0xMjUuMTcgMjAwLjc3YTY2LjUgNjYuNSAwIDAwMS43MjYuMjM0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzM4LCAxMDAlLCA1MCUpIiBkPSJNMTI0LjAyNCAyMDAuNTg4YTY2LjUgNjYuNSAwIDAwMS43MjEuMjY1Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzM5LCAxMDAlLCA1MCUpIiBkPSJNMTIyLjg4MSAyMDAuMzg2YTY2LjUgNjYuNSAwIDAwMS43MTYuMjk1Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzQwLCAxMDAlLCA1MCUpIiBkPSJNMTIxLjc0MiAyMDAuMTY1YTY2LjUgNjYuNSAwIDAwMS43MS4zMjUiLz48cGF0aCBzdHJva2U9ImhzbCgzNDEsIDEwMCUsIDUwJSkiIGQ9Ik0xMjAuNjA3IDE5OS45MjRhNjYuNSA2Ni41IDAgMDAxLjcwNC4zNTQiLz48cGF0aCBzdHJva2U9ImhzbCgzNDIsIDEwMCUsIDUwJSkiIGQ9Ik0xMTkuNDc2IDE5OS42NjNhNjYuNSA2Ni41IDAgMDAxLjY5OC4zODQiLz48cGF0aCBzdHJva2U9ImhzbCgzNDMsIDEwMCUsIDUwJSkiIGQ9Ik0xMTguMzUgMTk5LjM4MmE2Ni41IDY2LjUgMCAwMDEuNjkuNDE0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzQ0LCAxMDAlLCA1MCUpIiBkPSJNMTE3LjIyOSAxOTkuMDgxYTY2LjUgNjYuNSAwIDAwMS42ODMuNDQ0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzQ1LCAxMDAlLCA1MCUpIiBkPSJNMTE2LjExMyAxOTguNzYyYTY2LjUgNjYuNSAwIDAwMS42NzYuNDcyIi8+PHBhdGggc3Ryb2tlPSJoc2woMzQ2LCAxMDAlLCA1MCUpIiBkPSJNMTE1LjAwMyAxOTguNDIyYTY2LjUgNjYuNSAwIDAwMS42NjcuNTAyIi8+PHBhdGggc3Ryb2tlPSJoc2woMzQ3LCAxMDAlLCA1MCUpIiBkPSJNMTEzLjkgMTk4LjA2NGE2Ni41IDY2LjUgMCAwMDEuNjU3LjUzIi8+PHBhdGggc3Ryb2tlPSJoc2woMzQ4LCAxMDAlLCA1MCUpIiBkPSJNMTEyLjgwMiAxOTcuNjg2YTY2LjUgNjYuNSAwIDAwMS42NDguNTYiLz48cGF0aCBzdHJva2U9ImhzbCgzNDksIDEwMCUsIDUwJSkiIGQ9Ik0xMTEuNzExIDE5Ny4yODlhNjYuNSA2Ni41IDAgMDAxLjYzOS41ODgiLz48cGF0aCBzdHJva2U9ImhzbCgzNTAsIDEwMCUsIDUwJSkiIGQ9Ik0xMTAuNjI4IDE5Ni44NzNhNjYuNSA2Ni41IDAgMDAxLjYyOC42MTciLz48cGF0aCBzdHJva2U9ImhzbCgzNTEsIDEwMCUsIDUwJSkiIGQ9Ik0xMDkuNTUyIDE5Ni40MzhhNjYuNSA2Ni41IDAgMDAxLjYxNy42NDUiLz48cGF0aCBzdHJva2U9ImhzbCgzNTIsIDEwMCUsIDUwJSkiIGQ9Ik0xMDguNDgzIDE5NS45ODRhNjYuNSA2Ni41IDAgMDAxLjYwNi42NzQiLz48cGF0aCBzdHJva2U9ImhzbCgzNTMsIDEwMCUsIDUwJSkiIGQ9Ik0xMDcuNDIzIDE5NS41MTJhNjYuNSA2Ni41IDAgMDAxLjU5My43MDIiLz48cGF0aCBzdHJva2U9ImhzbCgzNTQsIDEwMCUsIDUwJSkiIGQ9Ik0xMDYuMzcxIDE5NS4wMjJhNjYuNSA2Ni41IDAgMDAxLjU4MS43MjkiLz48cGF0aCBzdHJva2U9ImhzbCgzNTUsIDEwMCUsIDUwJSkiIGQ9Ik0xMDUuMzI4IDE5NC41MTNhNjYuNSA2Ni41IDAgMDAxLjU2OC43NTYiLz48cGF0aCBzdHJva2U9ImhzbCgzNTYsIDEwMCUsIDUwJSkiIGQ9Ik0xMDQuMjk0IDE5My45ODZhNjYuNSA2Ni41IDAgMDAxLjU1NC43ODQiLz48cGF0aCBzdHJva2U9ImhzbCgzNTcsIDEwMCUsIDUwJSkiIGQ9Ik0xMDMuMjY5IDE5My40NDFhNjYuNSA2Ni41IDAgMDAxLjU0LjgxIi8+PHBhdGggc3Ryb2tlPSJoc2woMzU4LCAxMDAlLCA1MCUpIiBkPSJNMTAyLjI1NCAxOTIuODc5YTY2LjUgNjYuNSAwIDAwMS41MjYuODM3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzU5LCAxMDAlLCA1MCUpIiBkPSJNMTAxLjI0OSAxOTIuMjk4YTY2LjUgNjYuNSAwIDAwMS41MTEuODY0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMCwgMTAwJSwgNTAlKSIgZD0iTTEwMC4yNTQgMTkxLjdhNjYuNSA2Ni41IDAgMDAxLjQ5Ni44OSIvPjxwYXRoIHN0cm9rZT0iaHNsKDEsIDEwMCUsIDUwJSkiIGQ9Ik05OS4yNyAxOTEuMDg2YTY2LjUgNjYuNSAwIDAwMS40OC45MTYiLz48cGF0aCBzdHJva2U9ImhzbCgyLCAxMDAlLCA1MCUpIiBkPSJNOTguMjk2IDE5MC40NTNhNjYuNSA2Ni41IDAgMDAxLjQ2NC45NDIiLz48cGF0aCBzdHJva2U9ImhzbCgzLCAxMDAlLCA1MCUpIiBkPSJNOTcuMzM0IDE4OS44MDRhNjYuNSA2Ni41IDAgMDAxLjQ0OC45NjgiLz48cGF0aCBzdHJva2U9ImhzbCg0LCAxMDAlLCA1MCUpIiBkPSJNOTYuMzgzIDE4OS4xMzlhNjYuNSA2Ni41IDAgMDAxLjQzLjk5MiIvPjxwYXRoIHN0cm9rZT0iaHNsKDUsIDEwMCUsIDUwJSkiIGQ9Ik05NS40NDQgMTg4LjQ1NmE2Ni41IDY2LjUgMCAwMDEuNDEzIDEuMDE4Ii8+PHBhdGggc3Ryb2tlPSJoc2woNiwgMTAwJSwgNTAlKSIgZD0iTTk0LjUxNyAxODcuNzU4YTY2LjUgNjYuNSAwIDAwMS4zOTUgMS4wNDIiLz48cGF0aCBzdHJva2U9ImhzbCg3LCAxMDAlLCA1MCUpIiBkPSJNOTMuNjAzIDE4Ny4wNDNhNjYuNSA2Ni41IDAgMDAxLjM3NiAxLjA2NiIvPjxwYXRoIHN0cm9rZT0iaHNsKDgsIDEwMCUsIDUwJSkiIGQ9Ik05Mi43IDE4Ni4zMTNhNjYuNSA2Ni41IDAgMDAxLjM1OSAxLjA5Ii8+PHBhdGggc3Ryb2tlPSJoc2woOSwgMTAwJSwgNTAlKSIgZD0iTTkxLjgxMiAxODUuNTY3YTY2LjUgNjYuNSAwIDAwMS4zMzggMS4xMTMiLz48cGF0aCBzdHJva2U9ImhzbCgxMCwgMTAwJSwgNTAlKSIgZD0iTTkwLjkzNiAxODQuODA2YTY2LjUgNjYuNSAwIDAwMS4zMTkgMS4xMzYiLz48cGF0aCBzdHJva2U9ImhzbCgxMSwgMTAwJSwgNTAlKSIgZD0iTTkwLjA3MyAxODQuMDI5YTY2LjUgNjYuNSAwIDAwMS4zIDEuMTYiLz48cGF0aCBzdHJva2U9ImhzbCgxMiwgMTAwJSwgNTAlKSIgZD0iTTg5LjIyNCAxODMuMjM3YTY2LjUgNjYuNSAwIDAwMS4yNzkgMS4xODIiLz48cGF0aCBzdHJva2U9ImhzbCgxMywgMTAwJSwgNTAlKSIgZD0iTTg4LjM5IDE4Mi40MzFhNjYuNSA2Ni41IDAgMDAxLjI1NyAxLjIwNCIvPjxwYXRoIHN0cm9rZT0iaHNsKDE0LCAxMDAlLCA1MCUpIiBkPSJNODcuNTY5IDE4MS42MWE2Ni41IDY2LjUgMCAwMDEuMjM2IDEuMjI2Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTUsIDEwMCUsIDUwJSkiIGQ9Ik04Ni43NjMgMTgwLjc3NmE2Ni41IDY2LjUgMCAwMDEuMjE0IDEuMjQ3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTYsIDEwMCUsIDUwJSkiIGQ9Ik04NS45NzEgMTc5LjkyN2E2Ni41IDY2LjUgMCAwMDEuMTkzIDEuMjY4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTcsIDEwMCUsIDUwJSkiIGQ9Ik04NS4xOTQgMTc5LjA2NGE2Ni41IDY2LjUgMCAwMDEuMTcxIDEuMjg5Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTgsIDEwMCUsIDUwJSkiIGQ9Ik04NC40MzMgMTc4LjE4OGE2Ni41IDY2LjUgMCAwMDEuMTQ4IDEuMzEiLz48cGF0aCBzdHJva2U9ImhzbCgxOSwgMTAwJSwgNTAlKSIgZD0iTTgzLjY4NyAxNzcuM2E2Ni41IDY2LjUgMCAwMDEuMTI1IDEuMzI4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjAsIDEwMCUsIDUwJSkiIGQ9Ik04Mi45NTcgMTc2LjM5N2E2Ni41IDY2LjUgMCAwMDEuMTAxIDEuMzQ4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjEsIDEwMCUsIDUwJSkiIGQ9Ik04Mi4yNDIgMTc1LjQ4M2E2Ni41IDY2LjUgMCAwMDEuMDc4IDEuMzY3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjIsIDEwMCUsIDUwJSkiIGQ9Ik04MS41NDQgMTc0LjU1NmE2Ni41IDY2LjUgMCAwMDEuMDUzIDEuMzg1Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjMsIDEwMCUsIDUwJSkiIGQ9Ik04MC44NjEgMTczLjYxN2E2Ni41IDY2LjUgMCAwMDEuMDMgMS40MDQiLz48cGF0aCBzdHJva2U9ImhzbCgyNCwgMTAwJSwgNTAlKSIgZD0iTTgwLjE5NiAxNzIuNjY2YTY2LjUgNjYuNSAwIDAwMS4wMDQgMS40MjIiLz48cGF0aCBzdHJva2U9ImhzbCgyNSwgMTAwJSwgNTAlKSIgZD0iTTc5LjU0NyAxNzEuNzA0YTY2LjUgNjYuNSAwIDAwLjk4IDEuNDM5Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjYsIDEwMCUsIDUwJSkiIGQ9Ik03OC45MTQgMTcwLjczYTY2LjUgNjYuNSAwIDAwLjk1NSAxLjQ1NiIvPjxwYXRoIHN0cm9rZT0iaHNsKDI3LCAxMDAlLCA1MCUpIiBkPSJNNzguMyAxNjkuNzQ2YTY2LjUgNjYuNSAwIDAwLjkyOCAxLjQ3MiIvPjxwYXRoIHN0cm9rZT0iaHNsKDI4LCAxMDAlLCA1MCUpIiBkPSJNNzcuNzAyIDE2OC43NTFhNjYuNSA2Ni41IDAgMDAuOTAzIDEuNDg5Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjksIDEwMCUsIDUwJSkiIGQ9Ik03Ny4xMjEgMTY3Ljc0NmE2Ni41IDY2LjUgMCAwMC44NzcgMS41MDQiLz48cGF0aCBzdHJva2U9ImhzbCgzMCwgMTAwJSwgNTAlKSIgZD0iTTc2LjU1OSAxNjYuNzMxYTY2LjUgNjYuNSAwIDAwLjg1IDEuNTE5Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzEsIDEwMCUsIDUwJSkiIGQ9Ik03Ni4wMTQgMTY1LjcwNmE2Ni41IDY2LjUgMCAwMC44MjQgMS41MzQiLz48cGF0aCBzdHJva2U9ImhzbCgzMiwgMTAwJSwgNTAlKSIgZD0iTTc1LjQ4NyAxNjQuNjcyYTY2LjUgNjYuNSAwIDAwLjc5NyAxLjU0OCIvPjxwYXRoIHN0cm9rZT0iaHNsKDMzLCAxMDAlLCA1MCUpIiBkPSJNNzQuOTc4IDE2My42MjlhNjYuNSA2Ni41IDAgMDAuNzcgMS41NjEiLz48cGF0aCBzdHJva2U9ImhzbCgzNCwgMTAwJSwgNTAlKSIgZD0iTTc0LjQ4OCAxNjIuNTc3YTY2LjUgNjYuNSAwIDAwLjc0MiAxLjU3NSIvPjxwYXRoIHN0cm9rZT0iaHNsKDM1LCAxMDAlLCA1MCUpIiBkPSJNNzQuMDE2IDE2MS41MTdhNjYuNSA2Ni41IDAgMDAuNzE1IDEuNTg3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzYsIDEwMCUsIDUwJSkiIGQ9Ik03My41NjIgMTYwLjQ0OGE2Ni41IDY2LjUgMCAwMC42ODcgMS42Ii8+PHBhdGggc3Ryb2tlPSJoc2woMzcsIDEwMCUsIDUwJSkiIGQ9Ik03My4xMjcgMTU5LjM3MmE2Ni41IDY2LjUgMCAwMC42NiAxLjYxMiIvPjxwYXRoIHN0cm9rZT0iaHNsKDM4LCAxMDAlLCA1MCUpIiBkPSJNNzIuNzExIDE1OC4yODlhNjYuNSA2Ni41IDAgMDAuNjMxIDEuNjIyIi8+PHBhdGggc3Ryb2tlPSJoc2woMzksIDEwMCUsIDUwJSkiIGQ9Ik03Mi4zMTQgMTU3LjE5OGE2Ni41IDY2LjUgMCAwMC42MDMgMS42MzMiLz48cGF0aCBzdHJva2U9ImhzbCg0MCwgMTAwJSwgNTAlKSIgZD0iTTcxLjkzNiAxNTYuMWE2Ni41IDY2LjUgMCAwMC41NzQgMS42NDQiLz48cGF0aCBzdHJva2U9ImhzbCg0MSwgMTAwJSwgNTAlKSIgZD0iTTcxLjU3OCAxNTQuOTk3YTY2LjUgNjYuNSAwIDAwLjU0NSAxLjY1MyIvPjxwYXRoIHN0cm9rZT0iaHNsKDQyLCAxMDAlLCA1MCUpIiBkPSJNNzEuMjM4IDE1My44ODdhNjYuNSA2Ni41IDAgMDAuNTE3IDEuNjYzIi8+PHBhdGggc3Ryb2tlPSJoc2woNDMsIDEwMCUsIDUwJSkiIGQ9Ik03MC45MTkgMTUyLjc3MWE2Ni41IDY2LjUgMCAwMC40ODcgMS42NzIiLz48cGF0aCBzdHJva2U9ImhzbCg0NCwgMTAwJSwgNTAlKSIgZD0iTTcwLjYxOCAxNTEuNjVhNjYuNSA2Ni41IDAgMDAuNDU4IDEuNjgiLz48cGF0aCBzdHJva2U9ImhzbCg0NSwgMTAwJSwgNTAlKSIgZD0iTTcwLjMzNyAxNTAuNTI0YTY2LjUgNjYuNSAwIDAwLjQyOSAxLjY4NyIvPjxwYXRoIHN0cm9rZT0iaHNsKDQ2LCAxMDAlLCA1MCUpIiBkPSJNNzAuMDc2IDE0OS4zOTNhNjYuNSA2Ni41IDAgMDAuNCAxLjY5NSIvPjxwYXRoIHN0cm9rZT0iaHNsKDQ3LCAxMDAlLCA1MCUpIiBkPSJNNjkuODM1IDE0OC4yNThhNjYuNSA2Ni41IDAgMDAuMzcgMS43MDEiLz48cGF0aCBzdHJva2U9ImhzbCg0OCwgMTAwJSwgNTAlKSIgZD0iTTY5LjYxNCAxNDcuMTE5YTY2LjUgNjYuNSAwIDAwLjM0IDEuNzA3Ii8+PHBhdGggc3Ryb2tlPSJoc2woNDksIDEwMCUsIDUwJSkiIGQ9Ik02OS40MTIgMTQ1Ljk3NmE2Ni41IDY2LjUgMCAwMC4zMSAxLjcxMyIvPjxwYXRoIHN0cm9rZT0iaHNsKDUwLCAxMDAlLCA1MCUpIiBkPSJNNjkuMjMgMTQ0LjgzYTY2LjUgNjYuNSAwIDAwLjI4IDEuNzE4Ii8+PHBhdGggc3Ryb2tlPSJoc2woNTEsIDEwMCUsIDUwJSkiIGQ9Ik02OS4wNjkgMTQzLjY4YTY2LjUgNjYuNSAwIDAwLjI1IDEuNzIzIi8+PHBhdGggc3Ryb2tlPSJoc2woNTIsIDEwMCUsIDUwJSkiIGQ9Ik02OC45MjcgMTQyLjUyOGE2Ni41IDY2LjUgMCAwMC4yMiAxLjcyNyIvPjxwYXRoIHN0cm9rZT0iaHNsKDUzLCAxMDAlLCA1MCUpIiBkPSJNNjguODA2IDE0MS4zNzRhNjYuNSA2Ni41IDAgMDAuMTkgMS43MyIvPjxwYXRoIHN0cm9rZT0iaHNsKDU0LCAxMDAlLCA1MCUpIiBkPSJNNjguNzA1IDE0MC4yMThhNjYuNSA2Ni41IDAgMDAuMTYgMS43MzMiLz48cGF0aCBzdHJva2U9ImhzbCg1NSwgMTAwJSwgNTAlKSIgZD0iTTY4LjYyNCAxMzkuMDZhNjYuNSA2Ni41IDAgMDAuMTMgMS43MzYiLz48cGF0aCBzdHJva2U9ImhzbCg1NiwgMTAwJSwgNTAlKSIgZD0iTTY4LjU2MyAxMzcuOWE2Ni41IDY2LjUgMCAwMC4wOTkgMS43MzkiLz48cGF0aCBzdHJva2U9ImhzbCg1NywgMTAwJSwgNTAlKSIgZD0iTTY4LjUyMyAxMzYuNzRhNjYuNSA2Ni41IDAgMDAuMDY4IDEuNzQiLz48cGF0aCBzdHJva2U9ImhzbCg1OCwgMTAwJSwgNTAlKSIgZD0iTTY4LjUwMyAxMzUuNThhNjYuNSA2Ni41IDAgMDAuMDM4IDEuNzQiLz48cGF0aCBzdHJva2U9ImhzbCg1OSwgMTAwJSwgNTAlKSIgZD0iTTY4LjUwMyAxMzQuNDJhNjYuNSA2Ni41IDAgMDAuMDA3IDEuNzQiLz48cGF0aCBzdHJva2U9ImhzbCg2MCwgMTAwJSwgNTAlKSIgZD0iTTY4LjUyMyAxMzMuMjZBNjYuNSA2Ni41IDAgMDA2OC41IDEzNSIvPjxwYXRoIHN0cm9rZT0iaHNsKDYxLCAxMDAlLCA1MCUpIiBkPSJNNjguNTYzIDEzMi4xYTY2LjUgNjYuNSAwIDAwLS4wNTMgMS43NCIvPjxwYXRoIHN0cm9rZT0iaHNsKDYyLCAxMDAlLCA1MCUpIiBkPSJNNjguNjI0IDEzMC45NGE2Ni41IDY2LjUgMCAwMC0uMDgzIDEuNzQiLz48cGF0aCBzdHJva2U9ImhzbCg2MywgMTAwJSwgNTAlKSIgZD0iTTY4LjcwNSAxMjkuNzgyYTY2LjUgNjYuNSAwIDAwLS4xMTQgMS43MzgiLz48cGF0aCBzdHJva2U9ImhzbCg2NCwgMTAwJSwgNTAlKSIgZD0iTTY4LjgwNiAxMjguNjI2YTY2LjUgNjYuNSAwIDAwLS4xNDQgMS43MzUiLz48cGF0aCBzdHJva2U9ImhzbCg2NSwgMTAwJSwgNTAlKSIgZD0iTTY4LjkyNyAxMjcuNDcyYTY2LjUgNjYuNSAwIDAwLS4xNzQgMS43MzIiLz48cGF0aCBzdHJva2U9ImhzbCg2NiwgMTAwJSwgNTAlKSIgZD0iTTY5LjA2OSAxMjYuMzJhNjYuNSA2Ni41IDAgMDAtLjIwNSAxLjcyOSIvPjxwYXRoIHN0cm9rZT0iaHNsKDY3LCAxMDAlLCA1MCUpIiBkPSJNNjkuMjMgMTI1LjE3YTY2LjUgNjYuNSAwIDAwLS4yMzQgMS43MjYiLz48cGF0aCBzdHJva2U9ImhzbCg2OCwgMTAwJSwgNTAlKSIgZD0iTTY5LjQxMiAxMjQuMDI0YTY2LjUgNjYuNSAwIDAwLS4yNjUgMS43MjEiLz48cGF0aCBzdHJva2U9ImhzbCg2OSwgMTAwJSwgNTAlKSIgZD0iTTY5LjYxNCAxMjIuODgxYTY2LjUgNjYuNSAwIDAwLS4yOTUgMS43MTYiLz48cGF0aCBzdHJva2U9ImhzbCg3MCwgMTAwJSwgNTAlKSIgZD0iTTY5LjgzNSAxMjEuNzQyYTY2LjUgNjYuNSAwIDAwLS4zMjUgMS43MSIvPjxwYXRoIHN0cm9rZT0iaHNsKDcxLCAxMDAlLCA1MCUpIiBkPSJNNzAuMDc2IDEyMC42MDdhNjYuNSA2Ni41IDAgMDAtLjM1NCAxLjcwNCIvPjxwYXRoIHN0cm9rZT0iaHNsKDcyLCAxMDAlLCA1MCUpIiBkPSJNNzAuMzM3IDExOS40NzZhNjYuNSA2Ni41IDAgMDAtLjM4NCAxLjY5OCIvPjxwYXRoIHN0cm9rZT0iaHNsKDczLCAxMDAlLCA1MCUpIiBkPSJNNzAuNjE4IDExOC4zNWE2Ni41IDY2LjUgMCAwMC0uNDE0IDEuNjkiLz48cGF0aCBzdHJva2U9ImhzbCg3NCwgMTAwJSwgNTAlKSIgZD0iTTcwLjkxOSAxMTcuMjI5YTY2LjUgNjYuNSAwIDAwLS40NDQgMS42ODMiLz48cGF0aCBzdHJva2U9ImhzbCg3NSwgMTAwJSwgNTAlKSIgZD0iTTcxLjIzOCAxMTYuMTEzYTY2LjUgNjYuNSAwIDAwLS40NzIgMS42NzYiLz48cGF0aCBzdHJva2U9ImhzbCg3NiwgMTAwJSwgNTAlKSIgZD0iTTcxLjU3OCAxMTUuMDAzYTY2LjUgNjYuNSAwIDAwLS41MDIgMS42NjciLz48cGF0aCBzdHJva2U9ImhzbCg3NywgMTAwJSwgNTAlKSIgZD0iTTcxLjkzNiAxMTMuOWE2Ni41IDY2LjUgMCAwMC0uNTMgMS42NTciLz48cGF0aCBzdHJva2U9ImhzbCg3OCwgMTAwJSwgNTAlKSIgZD0iTTcyLjMxNCAxMTIuODAyYTY2LjUgNjYuNSAwIDAwLS41NiAxLjY0OCIvPjxwYXRoIHN0cm9rZT0iaHNsKDc5LCAxMDAlLCA1MCUpIiBkPSJNNzIuNzExIDExMS43MTFhNjYuNSA2Ni41IDAgMDAtLjU4OCAxLjYzOSIvPjxwYXRoIHN0cm9rZT0iaHNsKDgwLCAxMDAlLCA1MCUpIiBkPSJNNzMuMTI3IDExMC42MjhhNjYuNSA2Ni41IDAgMDAtLjYxNyAxLjYyOCIvPjxwYXRoIHN0cm9rZT0iaHNsKDgxLCAxMDAlLCA1MCUpIiBkPSJNNzMuNTYyIDEwOS41NTJhNjYuNSA2Ni41IDAgMDAtLjY0NSAxLjYxNyIvPjxwYXRoIHN0cm9rZT0iaHNsKDgyLCAxMDAlLCA1MCUpIiBkPSJNNzQuMDE2IDEwOC40ODNhNjYuNSA2Ni41IDAgMDAtLjY3NCAxLjYwNiIvPjxwYXRoIHN0cm9rZT0iaHNsKDgzLCAxMDAlLCA1MCUpIiBkPSJNNzQuNDg4IDEwNy40MjNhNjYuNSA2Ni41IDAgMDAtLjcwMiAxLjU5MyIvPjxwYXRoIHN0cm9rZT0iaHNsKDg0LCAxMDAlLCA1MCUpIiBkPSJNNzQuOTc4IDEwNi4zNzFhNjYuNSA2Ni41IDAgMDAtLjcyOSAxLjU4MSIvPjxwYXRoIHN0cm9rZT0iaHNsKDg1LCAxMDAlLCA1MCUpIiBkPSJNNzUuNDg3IDEwNS4zMjhhNjYuNSA2Ni41IDAgMDAtLjc1NiAxLjU2OCIvPjxwYXRoIHN0cm9rZT0iaHNsKDg2LCAxMDAlLCA1MCUpIiBkPSJNNzYuMDE0IDEwNC4yOTRhNjYuNSA2Ni41IDAgMDAtLjc4NCAxLjU1NCIvPjxwYXRoIHN0cm9rZT0iaHNsKDg3LCAxMDAlLCA1MCUpIiBkPSJNNzYuNTU5IDEwMy4yNjlhNjYuNSA2Ni41IDAgMDAtLjgxIDEuNTQiLz48cGF0aCBzdHJva2U9ImhzbCg4OCwgMTAwJSwgNTAlKSIgZD0iTTc3LjEyMSAxMDIuMjU0YTY2LjUgNjYuNSAwIDAwLS44MzcgMS41MjYiLz48cGF0aCBzdHJva2U9ImhzbCg4OSwgMTAwJSwgNTAlKSIgZD0iTTc3LjcwMiAxMDEuMjQ5YTY2LjUgNjYuNSAwIDAwLS44NjQgMS41MTEiLz48cGF0aCBzdHJva2U9ImhzbCg5MCwgMTAwJSwgNTAlKSIgZD0iTTc4LjMgMTAwLjI1NGE2Ni41IDY2LjUgMCAwMC0uODkgMS40OTYiLz48cGF0aCBzdHJva2U9ImhzbCg5MSwgMTAwJSwgNTAlKSIgZD0iTTc4LjkxNCA5OS4yN2E2Ni41IDY2LjUgMCAwMC0uOTE2IDEuNDgiLz48cGF0aCBzdHJva2U9ImhzbCg5MiwgMTAwJSwgNTAlKSIgZD0iTTc5LjU0NyA5OC4yOTZhNjYuNSA2Ni41IDAgMDAtLjk0MiAxLjQ2NCIvPjxwYXRoIHN0cm9rZT0iaHNsKDkzLCAxMDAlLCA1MCUpIiBkPSJNODAuMTk2IDk3LjMzNGE2Ni41IDY2LjUgMCAwMC0uOTY4IDEuNDQ4Ii8+PHBhdGggc3Ryb2tlPSJoc2woOTQsIDEwMCUsIDUwJSkiIGQ9Ik04MC44NjEgOTYuMzgzYTY2LjUgNjYuNSAwIDAwLS45OTIgMS40MyIvPjxwYXRoIHN0cm9rZT0iaHNsKDk1LCAxMDAlLCA1MCUpIiBkPSJNODEuNTQ0IDk1LjQ0NGE2Ni41IDY2LjUgMCAwMC0xLjAxOCAxLjQxMyIvPjxwYXRoIHN0cm9rZT0iaHNsKDk2LCAxMDAlLCA1MCUpIiBkPSJNODIuMjQyIDk0LjUxN2E2Ni41IDY2LjUgMCAwMC0xLjA0MiAxLjM5NSIvPjxwYXRoIHN0cm9rZT0iaHNsKDk3LCAxMDAlLCA1MCUpIiBkPSJNODIuOTU3IDkzLjYwM2E2Ni41IDY2LjUgMCAwMC0xLjA2NiAxLjM3NiIvPjxwYXRoIHN0cm9rZT0iaHNsKDk4LCAxMDAlLCA1MCUpIiBkPSJNODMuNjg3IDkyLjdhNjYuNSA2Ni41IDAgMDAtMS4wOSAxLjM1OSIvPjxwYXRoIHN0cm9rZT0iaHNsKDk5LCAxMDAlLCA1MCUpIiBkPSJNODQuNDMzIDkxLjgxMmE2Ni41IDY2LjUgMCAwMC0xLjExMyAxLjMzOCIvPjxwYXRoIHN0cm9rZT0iaHNsKDEwMCwgMTAwJSwgNTAlKSIgZD0iTTg1LjE5NCA5MC45MzZhNjYuNSA2Ni41IDAgMDAtMS4xMzYgMS4zMTkiLz48cGF0aCBzdHJva2U9ImhzbCgxMDEsIDEwMCUsIDUwJSkiIGQ9Ik04NS45NzEgOTAuMDczYTY2LjUgNjYuNSAwIDAwLTEuMTYgMS4zIi8+PHBhdGggc3Ryb2tlPSJoc2woMTAyLCAxMDAlLCA1MCUpIiBkPSJNODYuNzYzIDg5LjIyNGE2Ni41IDY2LjUgMCAwMC0xLjE4MiAxLjI3OSIvPjxwYXRoIHN0cm9rZT0iaHNsKDEwMywgMTAwJSwgNTAlKSIgZD0iTTg3LjU2OSA4OC4zOWE2Ni41IDY2LjUgMCAwMC0xLjIwNCAxLjI1NyIvPjxwYXRoIHN0cm9rZT0iaHNsKDEwNCwgMTAwJSwgNTAlKSIgZD0iTTg4LjM5IDg3LjU2OWE2Ni41IDY2LjUgMCAwMC0xLjIyNiAxLjIzNiIvPjxwYXRoIHN0cm9rZT0iaHNsKDEwNSwgMTAwJSwgNTAlKSIgZD0iTTg5LjIyNCA4Ni43NjNhNjYuNSA2Ni41IDAgMDAtMS4yNDcgMS4yMTQiLz48cGF0aCBzdHJva2U9ImhzbCgxMDYsIDEwMCUsIDUwJSkiIGQ9Ik05MC4wNzMgODUuOTcxYTY2LjUgNjYuNSAwIDAwLTEuMjY4IDEuMTkzIi8+PHBhdGggc3Ryb2tlPSJoc2woMTA3LCAxMDAlLCA1MCUpIiBkPSJNOTAuOTM2IDg1LjE5NGE2Ni41IDY2LjUgMCAwMC0xLjI4OSAxLjE3MSIvPjxwYXRoIHN0cm9rZT0iaHNsKDEwOCwgMTAwJSwgNTAlKSIgZD0iTTkxLjgxMiA4NC40MzNhNjYuNSA2Ni41IDAgMDAtMS4zMSAxLjE0OCIvPjxwYXRoIHN0cm9rZT0iaHNsKDEwOSwgMTAwJSwgNTAlKSIgZD0iTTkyLjcgODMuNjg3YTY2LjUgNjYuNSAwIDAwLTEuMzI4IDEuMTI1Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTEwLCAxMDAlLCA1MCUpIiBkPSJNOTMuNjAzIDgyLjk1N2E2Ni41IDY2LjUgMCAwMC0xLjM0OCAxLjEwMSIvPjxwYXRoIHN0cm9rZT0iaHNsKDExMSwgMTAwJSwgNTAlKSIgZD0iTTk0LjUxNyA4Mi4yNDJhNjYuNSA2Ni41IDAgMDAtMS4zNjcgMS4wNzgiLz48cGF0aCBzdHJva2U9ImhzbCgxMTIsIDEwMCUsIDUwJSkiIGQ9Ik05NS40NDQgODEuNTQ0YTY2LjUgNjYuNSAwIDAwLTEuMzg1IDEuMDUzIi8+PHBhdGggc3Ryb2tlPSJoc2woMTEzLCAxMDAlLCA1MCUpIiBkPSJNOTYuMzgzIDgwLjg2MWE2Ni41IDY2LjUgMCAwMC0xLjQwNCAxLjAzIi8+PHBhdGggc3Ryb2tlPSJoc2woMTE0LCAxMDAlLCA1MCUpIiBkPSJNOTcuMzM0IDgwLjE5NmE2Ni41IDY2LjUgMCAwMC0xLjQyMiAxLjAwNCIvPjxwYXRoIHN0cm9rZT0iaHNsKDExNSwgMTAwJSwgNTAlKSIgZD0iTTk4LjI5NiA3OS41NDdhNjYuNSA2Ni41IDAgMDAtMS40MzkuOTgiLz48cGF0aCBzdHJva2U9ImhzbCgxMTYsIDEwMCUsIDUwJSkiIGQ9Ik05OS4yNyA3OC45MTRhNjYuNSA2Ni41IDAgMDAtMS40NTYuOTU1Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTE3LCAxMDAlLCA1MCUpIiBkPSJNMTAwLjI1NCA3OC4zYTY2LjUgNjYuNSAwIDAwLTEuNDcyLjkyOCIvPjxwYXRoIHN0cm9rZT0iaHNsKDExOCwgMTAwJSwgNTAlKSIgZD0iTTEwMS4yNDkgNzcuNzAyYTY2LjUgNjYuNSAwIDAwLTEuNDg5LjkwMyIvPjxwYXRoIHN0cm9rZT0iaHNsKDExOSwgMTAwJSwgNTAlKSIgZD0iTTEwMi4yNTQgNzcuMTIxYTY2LjUgNjYuNSAwIDAwLTEuNTA0Ljg3NyIvPjxwYXRoIHN0cm9rZT0iaHNsKDEyMCwgMTAwJSwgNTAlKSIgZD0iTTEwMy4yNjkgNzYuNTU5YTY2LjUgNjYuNSAwIDAwLTEuNTE5Ljg1Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTIxLCAxMDAlLCA1MCUpIiBkPSJNMTA0LjI5NCA3Ni4wMTRhNjYuNSA2Ni41IDAgMDAtMS41MzQuODI0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTIyLCAxMDAlLCA1MCUpIiBkPSJNMTA1LjMyOCA3NS40ODdhNjYuNSA2Ni41IDAgMDAtMS41NDguNzk3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTIzLCAxMDAlLCA1MCUpIiBkPSJNMTA2LjM3MSA3NC45NzhhNjYuNSA2Ni41IDAgMDAtMS41NjEuNzciLz48cGF0aCBzdHJva2U9ImhzbCgxMjQsIDEwMCUsIDUwJSkiIGQ9Ik0xMDcuNDIzIDc0LjQ4OGE2Ni41IDY2LjUgMCAwMC0xLjU3NS43NDIiLz48cGF0aCBzdHJva2U9ImhzbCgxMjUsIDEwMCUsIDUwJSkiIGQ9Ik0xMDguNDgzIDc0LjAxNmE2Ni41IDY2LjUgMCAwMC0xLjU4Ny43MTUiLz48cGF0aCBzdHJva2U9ImhzbCgxMjYsIDEwMCUsIDUwJSkiIGQ9Ik0xMDkuNTUyIDczLjU2MmE2Ni41IDY2LjUgMCAwMC0xLjYuNjg3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTI3LCAxMDAlLCA1MCUpIiBkPSJNMTEwLjYyOCA3My4xMjdhNjYuNSA2Ni41IDAgMDAtMS42MTIuNjYiLz48cGF0aCBzdHJva2U9ImhzbCgxMjgsIDEwMCUsIDUwJSkiIGQ9Ik0xMTEuNzExIDcyLjcxMWE2Ni41IDY2LjUgMCAwMC0xLjYyMi42MzEiLz48cGF0aCBzdHJva2U9ImhzbCgxMjksIDEwMCUsIDUwJSkiIGQ9Ik0xMTIuODAyIDcyLjMxNGE2Ni41IDY2LjUgMCAwMC0xLjYzMy42MDMiLz48cGF0aCBzdHJva2U9ImhzbCgxMzAsIDEwMCUsIDUwJSkiIGQ9Ik0xMTMuOSA3MS45MzZhNjYuNSA2Ni41IDAgMDAtMS42NDQuNTc0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTMxLCAxMDAlLCA1MCUpIiBkPSJNMTE1LjAwMyA3MS41NzhhNjYuNSA2Ni41IDAgMDAtMS42NTMuNTQ1Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTMyLCAxMDAlLCA1MCUpIiBkPSJNMTE2LjExMyA3MS4yMzhhNjYuNSA2Ni41IDAgMDAtMS42NjMuNTE3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTMzLCAxMDAlLCA1MCUpIiBkPSJNMTE3LjIyOSA3MC45MTlhNjYuNSA2Ni41IDAgMDAtMS42NzIuNDg3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTM0LCAxMDAlLCA1MCUpIiBkPSJNMTE4LjM1IDcwLjYxOGE2Ni41IDY2LjUgMCAwMC0xLjY4LjQ1OCIvPjxwYXRoIHN0cm9rZT0iaHNsKDEzNSwgMTAwJSwgNTAlKSIgZD0iTTExOS40NzYgNzAuMzM3YTY2LjUgNjYuNSAwIDAwLTEuNjg3LjQyOSIvPjxwYXRoIHN0cm9rZT0iaHNsKDEzNiwgMTAwJSwgNTAlKSIgZD0iTTEyMC42MDcgNzAuMDc2YTY2LjUgNjYuNSAwIDAwLTEuNjk1LjQiLz48cGF0aCBzdHJva2U9ImhzbCgxMzcsIDEwMCUsIDUwJSkiIGQ9Ik0xMjEuNzQyIDY5LjgzNWE2Ni41IDY2LjUgMCAwMC0xLjcwMS4zNyIvPjxwYXRoIHN0cm9rZT0iaHNsKDEzOCwgMTAwJSwgNTAlKSIgZD0iTTEyMi44ODEgNjkuNjE0YTY2LjUgNjYuNSAwIDAwLTEuNzA3LjM0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTM5LCAxMDAlLCA1MCUpIiBkPSJNMTI0LjAyNCA2OS40MTJhNjYuNSA2Ni41IDAgMDAtMS43MTMuMzEiLz48cGF0aCBzdHJva2U9ImhzbCgxNDAsIDEwMCUsIDUwJSkiIGQ9Ik0xMjUuMTcgNjkuMjNhNjYuNSA2Ni41IDAgMDAtMS43MTguMjgiLz48cGF0aCBzdHJva2U9ImhzbCgxNDEsIDEwMCUsIDUwJSkiIGQ9Ik0xMjYuMzIgNjkuMDY5YTY2LjUgNjYuNSAwIDAwLTEuNzIzLjI1Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTQyLCAxMDAlLCA1MCUpIiBkPSJNMTI3LjQ3MiA2OC45MjdhNjYuNSA2Ni41IDAgMDAtMS43MjcuMjIiLz48cGF0aCBzdHJva2U9ImhzbCgxNDMsIDEwMCUsIDUwJSkiIGQ9Ik0xMjguNjI2IDY4LjgwNmE2Ni41IDY2LjUgMCAwMC0xLjczLjE5Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTQ0LCAxMDAlLCA1MCUpIiBkPSJNMTI5Ljc4MiA2OC43MDVhNjYuNSA2Ni41IDAgMDAtMS43MzMuMTYiLz48cGF0aCBzdHJva2U9ImhzbCgxNDUsIDEwMCUsIDUwJSkiIGQ9Ik0xMzAuOTQgNjguNjI0YTY2LjUgNjYuNSAwIDAwLTEuNzM2LjEzIi8+PHBhdGggc3Ryb2tlPSJoc2woMTQ2LCAxMDAlLCA1MCUpIiBkPSJNMTMyLjEgNjguNTYzYTY2LjUgNjYuNSAwIDAwLTEuNzM5LjA5OSIvPjxwYXRoIHN0cm9rZT0iaHNsKDE0NywgMTAwJSwgNTAlKSIgZD0iTTEzMy4yNiA2OC41MjNhNjYuNSA2Ni41IDAgMDAtMS43NC4wNjgiLz48cGF0aCBzdHJva2U9ImhzbCgxNDgsIDEwMCUsIDUwJSkiIGQ9Ik0xMzQuNDIgNjguNTAzYTY2LjUgNjYuNSAwIDAwLTEuNzQuMDM4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTQ5LCAxMDAlLCA1MCUpIiBkPSJNMTM1LjU4IDY4LjUwM2E2Ni41IDY2LjUgMCAwMC0xLjc0LjAwNyIvPjxwYXRoIHN0cm9rZT0iaHNsKDE1MCwgMTAwJSwgNTAlKSIgZD0iTTEzNi43NCA2OC41MjNBNjYuNSA2Ni41IDAgMDAxMzUgNjguNSIvPjxwYXRoIHN0cm9rZT0iaHNsKDE1MSwgMTAwJSwgNTAlKSIgZD0iTTEzNy45IDY4LjU2M2E2Ni41IDY2LjUgMCAwMC0xLjc0LS4wNTMiLz48cGF0aCBzdHJva2U9ImhzbCgxNTIsIDEwMCUsIDUwJSkiIGQ9Ik0xMzkuMDYgNjguNjI0YTY2LjUgNjYuNSAwIDAwLTEuNzQtLjA4MyIvPjxwYXRoIHN0cm9rZT0iaHNsKDE1MywgMTAwJSwgNTAlKSIgZD0iTTE0MC4yMTggNjguNzA1YTY2LjUgNjYuNSAwIDAwLTEuNzM4LS4xMTQiLz48cGF0aCBzdHJva2U9ImhzbCgxNTQsIDEwMCUsIDUwJSkiIGQ9Ik0xNDEuMzc0IDY4LjgwNmE2Ni41IDY2LjUgMCAwMC0xLjczNS0uMTQ0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTU1LCAxMDAlLCA1MCUpIiBkPSJNMTQyLjUyOCA2OC45MjdhNjYuNSA2Ni41IDAgMDAtMS43MzItLjE3NCIvPjxwYXRoIHN0cm9rZT0iaHNsKDE1NiwgMTAwJSwgNTAlKSIgZD0iTTE0My42OCA2OS4wNjlhNjYuNSA2Ni41IDAgMDAtMS43MjktLjIwNSIvPjxwYXRoIHN0cm9rZT0iaHNsKDE1NywgMTAwJSwgNTAlKSIgZD0iTTE0NC44MyA2OS4yM2E2Ni41IDY2LjUgMCAwMC0xLjcyNi0uMjM0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTU4LCAxMDAlLCA1MCUpIiBkPSJNMTQ1Ljk3NiA2OS40MTJhNjYuNSA2Ni41IDAgMDAtMS43MjEtLjI2NSIvPjxwYXRoIHN0cm9rZT0iaHNsKDE1OSwgMTAwJSwgNTAlKSIgZD0iTTE0Ny4xMTkgNjkuNjE0YTY2LjUgNjYuNSAwIDAwLTEuNzE2LS4yOTUiLz48cGF0aCBzdHJva2U9ImhzbCgxNjAsIDEwMCUsIDUwJSkiIGQ9Ik0xNDguMjU4IDY5LjgzNWE2Ni41IDY2LjUgMCAwMC0xLjcxLS4zMjUiLz48cGF0aCBzdHJva2U9ImhzbCgxNjEsIDEwMCUsIDUwJSkiIGQ9Ik0xNDkuMzkzIDcwLjA3NmE2Ni41IDY2LjUgMCAwMC0xLjcwNC0uMzU0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTYyLCAxMDAlLCA1MCUpIiBkPSJNMTUwLjUyNCA3MC4zMzdhNjYuNSA2Ni41IDAgMDAtMS42OTgtLjM4NCIvPjxwYXRoIHN0cm9rZT0iaHNsKDE2MywgMTAwJSwgNTAlKSIgZD0iTTE1MS42NSA3MC42MThhNjYuNSA2Ni41IDAgMDAtMS42OS0uNDE0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTY0LCAxMDAlLCA1MCUpIiBkPSJNMTUyLjc3MSA3MC45MTlhNjYuNSA2Ni41IDAgMDAtMS42ODMtLjQ0NCIvPjxwYXRoIHN0cm9rZT0iaHNsKDE2NSwgMTAwJSwgNTAlKSIgZD0iTTE1My44ODcgNzEuMjM4YTY2LjUgNjYuNSAwIDAwLTEuNjc2LS40NzIiLz48cGF0aCBzdHJva2U9ImhzbCgxNjYsIDEwMCUsIDUwJSkiIGQ9Ik0xNTQuOTk3IDcxLjU3OGE2Ni41IDY2LjUgMCAwMC0xLjY2Ny0uNTAyIi8+PHBhdGggc3Ryb2tlPSJoc2woMTY3LCAxMDAlLCA1MCUpIiBkPSJNMTU2LjEgNzEuOTM2YTY2LjUgNjYuNSAwIDAwLTEuNjU3LS41MyIvPjxwYXRoIHN0cm9rZT0iaHNsKDE2OCwgMTAwJSwgNTAlKSIgZD0iTTE1Ny4xOTggNzIuMzE0YTY2LjUgNjYuNSAwIDAwLTEuNjQ4LS41NiIvPjxwYXRoIHN0cm9rZT0iaHNsKDE2OSwgMTAwJSwgNTAlKSIgZD0iTTE1OC4yODkgNzIuNzExYTY2LjUgNjYuNSAwIDAwLTEuNjM5LS41ODgiLz48cGF0aCBzdHJva2U9ImhzbCgxNzAsIDEwMCUsIDUwJSkiIGQ9Ik0xNTkuMzcyIDczLjEyN2E2Ni41IDY2LjUgMCAwMC0xLjYyOC0uNjE3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTcxLCAxMDAlLCA1MCUpIiBkPSJNMTYwLjQ0OCA3My41NjJhNjYuNSA2Ni41IDAgMDAtMS42MTctLjY0NSIvPjxwYXRoIHN0cm9rZT0iaHNsKDE3MiwgMTAwJSwgNTAlKSIgZD0iTTE2MS41MTcgNzQuMDE2YTY2LjUgNjYuNSAwIDAwLTEuNjA2LS42NzQiLz48cGF0aCBzdHJva2U9ImhzbCgxNzMsIDEwMCUsIDUwJSkiIGQ9Ik0xNjIuNTc3IDc0LjQ4OGE2Ni41IDY2LjUgMCAwMC0xLjU5My0uNzAyIi8+PHBhdGggc3Ryb2tlPSJoc2woMTc0LCAxMDAlLCA1MCUpIiBkPSJNMTYzLjYyOSA3NC45NzhhNjYuNSA2Ni41IDAgMDAtMS41ODEtLjcyOSIvPjxwYXRoIHN0cm9rZT0iaHNsKDE3NSwgMTAwJSwgNTAlKSIgZD0iTTE2NC42NzIgNzUuNDg3YTY2LjUgNjYuNSAwIDAwLTEuNTY4LS43NTYiLz48cGF0aCBzdHJva2U9ImhzbCgxNzYsIDEwMCUsIDUwJSkiIGQ9Ik0xNjUuNzA2IDc2LjAxNGE2Ni41IDY2LjUgMCAwMC0xLjU1NC0uNzg0Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTc3LCAxMDAlLCA1MCUpIiBkPSJNMTY2LjczMSA3Ni41NTlhNjYuNSA2Ni41IDAgMDAtMS41NC0uODEiLz48cGF0aCBzdHJva2U9ImhzbCgxNzgsIDEwMCUsIDUwJSkiIGQ9Ik0xNjcuNzQ2IDc3LjEyMWE2Ni41IDY2LjUgMCAwMC0xLjUyNi0uODM3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTc5LCAxMDAlLCA1MCUpIiBkPSJNMTY4Ljc1MSA3Ny43MDJhNjYuNSA2Ni41IDAgMDAtMS41MTEtLjg2NCIvPjxwYXRoIHN0cm9rZT0iaHNsKDE4MCwgMTAwJSwgNTAlKSIgZD0iTTE2OS43NDYgNzguM2E2Ni41IDY2LjUgMCAwMC0xLjQ5Ni0uODkiLz48cGF0aCBzdHJva2U9ImhzbCgxODEsIDEwMCUsIDUwJSkiIGQ9Ik0xNzAuNzMgNzguOTE0YTY2LjUgNjYuNSAwIDAwLTEuNDgtLjkxNiIvPjxwYXRoIHN0cm9rZT0iaHNsKDE4MiwgMTAwJSwgNTAlKSIgZD0iTTE3MS43MDQgNzkuNTQ3YTY2LjUgNjYuNSAwIDAwLTEuNDY0LS45NDIiLz48cGF0aCBzdHJva2U9ImhzbCgxODMsIDEwMCUsIDUwJSkiIGQ9Ik0xNzIuNjY2IDgwLjE5NmE2Ni41IDY2LjUgMCAwMC0xLjQ0OC0uOTY4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTg0LCAxMDAlLCA1MCUpIiBkPSJNMTczLjYxNyA4MC44NjFhNjYuNSA2Ni41IDAgMDAtMS40My0uOTkyIi8+PHBhdGggc3Ryb2tlPSJoc2woMTg1LCAxMDAlLCA1MCUpIiBkPSJNMTc0LjU1NiA4MS41NDRhNjYuNSA2Ni41IDAgMDAtMS40MTMtMS4wMTgiLz48cGF0aCBzdHJva2U9ImhzbCgxODYsIDEwMCUsIDUwJSkiIGQ9Ik0xNzUuNDgzIDgyLjI0MmE2Ni41IDY2LjUgMCAwMC0xLjM5NS0xLjA0MiIvPjxwYXRoIHN0cm9rZT0iaHNsKDE4NywgMTAwJSwgNTAlKSIgZD0iTTE3Ni4zOTcgODIuOTU3YTY2LjUgNjYuNSAwIDAwLTEuMzc2LTEuMDY2Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTg4LCAxMDAlLCA1MCUpIiBkPSJNMTc3LjMgODMuNjg3YTY2LjUgNjYuNSAwIDAwLTEuMzU5LTEuMDkiLz48cGF0aCBzdHJva2U9ImhzbCgxODksIDEwMCUsIDUwJSkiIGQ9Ik0xNzguMTg4IDg0LjQzM2E2Ni41IDY2LjUgMCAwMC0xLjMzOC0xLjExMyIvPjxwYXRoIHN0cm9rZT0iaHNsKDE5MCwgMTAwJSwgNTAlKSIgZD0iTTE3OS4wNjQgODUuMTk0YTY2LjUgNjYuNSAwIDAwLTEuMzE5LTEuMTM2Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTkxLCAxMDAlLCA1MCUpIiBkPSJNMTc5LjkyNyA4NS45NzFhNjYuNSA2Ni41IDAgMDAtMS4zLTEuMTYiLz48cGF0aCBzdHJva2U9ImhzbCgxOTIsIDEwMCUsIDUwJSkiIGQ9Ik0xODAuNzc2IDg2Ljc2M2E2Ni41IDY2LjUgMCAwMC0xLjI3OS0xLjE4MiIvPjxwYXRoIHN0cm9rZT0iaHNsKDE5MywgMTAwJSwgNTAlKSIgZD0iTTE4MS42MSA4Ny41NjlhNjYuNSA2Ni41IDAgMDAtMS4yNTctMS4yMDQiLz48cGF0aCBzdHJva2U9ImhzbCgxOTQsIDEwMCUsIDUwJSkiIGQ9Ik0xODIuNDMxIDg4LjM5YTY2LjUgNjYuNSAwIDAwLTEuMjM2LTEuMjI2Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTk1LCAxMDAlLCA1MCUpIiBkPSJNMTgzLjIzNyA4OS4yMjRhNjYuNSA2Ni41IDAgMDAtMS4yMTQtMS4yNDciLz48cGF0aCBzdHJva2U9ImhzbCgxOTYsIDEwMCUsIDUwJSkiIGQ9Ik0xODQuMDI5IDkwLjA3M2E2Ni41IDY2LjUgMCAwMC0xLjE5My0xLjI2OCIvPjxwYXRoIHN0cm9rZT0iaHNsKDE5NywgMTAwJSwgNTAlKSIgZD0iTTE4NC44MDYgOTAuOTM2YTY2LjUgNjYuNSAwIDAwLTEuMTcxLTEuMjg5Ii8+PHBhdGggc3Ryb2tlPSJoc2woMTk4LCAxMDAlLCA1MCUpIiBkPSJNMTg1LjU2NyA5MS44MTJhNjYuNSA2Ni41IDAgMDAtMS4xNDgtMS4zMSIvPjxwYXRoIHN0cm9rZT0iaHNsKDE5OSwgMTAwJSwgNTAlKSIgZD0iTTE4Ni4zMTMgOTIuN2E2Ni41IDY2LjUgMCAwMC0xLjEyNS0xLjMyOCIvPjxwYXRoIHN0cm9rZT0iaHNsKDIwMCwgMTAwJSwgNTAlKSIgZD0iTTE4Ny4wNDMgOTMuNjAzYTY2LjUgNjYuNSAwIDAwLTEuMTAxLTEuMzQ4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjAxLCAxMDAlLCA1MCUpIiBkPSJNMTg3Ljc1OCA5NC41MTdhNjYuNSA2Ni41IDAgMDAtMS4wNzgtMS4zNjciLz48cGF0aCBzdHJva2U9ImhzbCgyMDIsIDEwMCUsIDUwJSkiIGQ9Ik0xODguNDU2IDk1LjQ0NGE2Ni41IDY2LjUgMCAwMC0xLjA1My0xLjM4NSIvPjxwYXRoIHN0cm9rZT0iaHNsKDIwMywgMTAwJSwgNTAlKSIgZD0iTTE4OS4xMzkgOTYuMzgzYTY2LjUgNjYuNSAwIDAwLTEuMDMtMS40MDQiLz48cGF0aCBzdHJva2U9ImhzbCgyMDQsIDEwMCUsIDUwJSkiIGQ9Ik0xODkuODA0IDk3LjMzNGE2Ni41IDY2LjUgMCAwMC0xLjAwNC0xLjQyMiIvPjxwYXRoIHN0cm9rZT0iaHNsKDIwNSwgMTAwJSwgNTAlKSIgZD0iTTE5MC40NTMgOTguMjk2YTY2LjUgNjYuNSAwIDAwLS45OC0xLjQzOSIvPjxwYXRoIHN0cm9rZT0iaHNsKDIwNiwgMTAwJSwgNTAlKSIgZD0iTTE5MS4wODYgOTkuMjdhNjYuNSA2Ni41IDAgMDAtLjk1NS0xLjQ1NiIvPjxwYXRoIHN0cm9rZT0iaHNsKDIwNywgMTAwJSwgNTAlKSIgZD0iTTE5MS43IDEwMC4yNTRhNjYuNSA2Ni41IDAgMDAtLjkyOC0xLjQ3MiIvPjxwYXRoIHN0cm9rZT0iaHNsKDIwOCwgMTAwJSwgNTAlKSIgZD0iTTE5Mi4yOTggMTAxLjI0OWE2Ni41IDY2LjUgMCAwMC0uOTAzLTEuNDg5Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjA5LCAxMDAlLCA1MCUpIiBkPSJNMTkyLjg3OSAxMDIuMjU0YTY2LjUgNjYuNSAwIDAwLS44NzctMS41MDQiLz48cGF0aCBzdHJva2U9ImhzbCgyMTAsIDEwMCUsIDUwJSkiIGQ9Ik0xOTMuNDQxIDEwMy4yNjlhNjYuNSA2Ni41IDAgMDAtLjg1LTEuNTE5Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjExLCAxMDAlLCA1MCUpIiBkPSJNMTkzLjk4NiAxMDQuMjk0YTY2LjUgNjYuNSAwIDAwLS44MjQtMS41MzQiLz48cGF0aCBzdHJva2U9ImhzbCgyMTIsIDEwMCUsIDUwJSkiIGQ9Ik0xOTQuNTEzIDEwNS4zMjhhNjYuNSA2Ni41IDAgMDAtLjc5Ny0xLjU0OCIvPjxwYXRoIHN0cm9rZT0iaHNsKDIxMywgMTAwJSwgNTAlKSIgZD0iTTE5NS4wMjIgMTA2LjM3MWE2Ni41IDY2LjUgMCAwMC0uNzctMS41NjEiLz48cGF0aCBzdHJva2U9ImhzbCgyMTQsIDEwMCUsIDUwJSkiIGQ9Ik0xOTUuNTEyIDEwNy40MjNhNjYuNSA2Ni41IDAgMDAtLjc0Mi0xLjU3NSIvPjxwYXRoIHN0cm9rZT0iaHNsKDIxNSwgMTAwJSwgNTAlKSIgZD0iTTE5NS45ODQgMTA4LjQ4M2E2Ni41IDY2LjUgMCAwMC0uNzE1LTEuNTg3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjE2LCAxMDAlLCA1MCUpIiBkPSJNMTk2LjQzOCAxMDkuNTUyYTY2LjUgNjYuNSAwIDAwLS42ODctMS42Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjE3LCAxMDAlLCA1MCUpIiBkPSJNMTk2Ljg3MyAxMTAuNjI4YTY2LjUgNjYuNSAwIDAwLS42Ni0xLjYxMiIvPjxwYXRoIHN0cm9rZT0iaHNsKDIxOCwgMTAwJSwgNTAlKSIgZD0iTTE5Ny4yODkgMTExLjcxMWE2Ni41IDY2LjUgMCAwMC0uNjMxLTEuNjIyIi8+PHBhdGggc3Ryb2tlPSJoc2woMjE5LCAxMDAlLCA1MCUpIiBkPSJNMTk3LjY4NiAxMTIuODAyYTY2LjUgNjYuNSAwIDAwLS42MDMtMS42MzMiLz48cGF0aCBzdHJva2U9ImhzbCgyMjAsIDEwMCUsIDUwJSkiIGQ9Ik0xOTguMDY0IDExMy45YTY2LjUgNjYuNSAwIDAwLS41NzQtMS42NDQiLz48cGF0aCBzdHJva2U9ImhzbCgyMjEsIDEwMCUsIDUwJSkiIGQ9Ik0xOTguNDIyIDExNS4wMDNhNjYuNSA2Ni41IDAgMDAtLjU0NS0xLjY1MyIvPjxwYXRoIHN0cm9rZT0iaHNsKDIyMiwgMTAwJSwgNTAlKSIgZD0iTTE5OC43NjIgMTE2LjExM2E2Ni41IDY2LjUgMCAwMC0uNTE3LTEuNjYzIi8+PHBhdGggc3Ryb2tlPSJoc2woMjIzLCAxMDAlLCA1MCUpIiBkPSJNMTk5LjA4MSAxMTcuMjI5YTY2LjUgNjYuNSAwIDAwLS40ODctMS42NzIiLz48cGF0aCBzdHJva2U9ImhzbCgyMjQsIDEwMCUsIDUwJSkiIGQ9Ik0xOTkuMzgyIDExOC4zNWE2Ni41IDY2LjUgMCAwMC0uNDU4LTEuNjgiLz48cGF0aCBzdHJva2U9ImhzbCgyMjUsIDEwMCUsIDUwJSkiIGQ9Ik0xOTkuNjYzIDExOS40NzZhNjYuNSA2Ni41IDAgMDAtLjQyOS0xLjY4NyIvPjxwYXRoIHN0cm9rZT0iaHNsKDIyNiwgMTAwJSwgNTAlKSIgZD0iTTE5OS45MjQgMTIwLjYwN2E2Ni41IDY2LjUgMCAwMC0uNC0xLjY5NSIvPjxwYXRoIHN0cm9rZT0iaHNsKDIyNywgMTAwJSwgNTAlKSIgZD0iTTIwMC4xNjUgMTIxLjc0MmE2Ni41IDY2LjUgMCAwMC0uMzctMS43MDEiLz48cGF0aCBzdHJva2U9ImhzbCgyMjgsIDEwMCUsIDUwJSkiIGQ9Ik0yMDAuMzg2IDEyMi44ODFhNjYuNSA2Ni41IDAgMDAtLjM0LTEuNzA3Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjI5LCAxMDAlLCA1MCUpIiBkPSJNMjAwLjU4OCAxMjQuMDI0YTY2LjUgNjYuNSAwIDAwLS4zMS0xLjcxMyIvPjxwYXRoIHN0cm9rZT0iaHNsKDIzMCwgMTAwJSwgNTAlKSIgZD0iTTIwMC43NyAxMjUuMTdhNjYuNSA2Ni41IDAgMDAtLjI4LTEuNzE4Ii8+PHBhdGggc3Ryb2tlPSJoc2woMjMxLCAxMDAlLCA1MCUpIiBkPSJNMjAwLjkzMSAxMjYuMzJhNjYuNSA2Ni41IDAgMDAtLjI1LTEuNzIzIi8+PHBhdGggc3Ryb2tlPSJoc2woMjMyLCAxMDAlLCA1MCUpIiBkPSJNMjAxLjA3MyAxMjcuNDcyYTY2LjUgNjYuNSAwIDAwLS4yMi0xLjcyNyIvPjxwYXRoIHN0cm9rZT0iaHNsKDIzMywgMTAwJSwgNTAlKSIgZD0iTTIwMS4xOTQgMTI4LjYyNmE2Ni41IDY2LjUgMCAwMC0uMTktMS43MyIvPjxwYXRoIHN0cm9rZT0iaHNsKDIzNCwgMTAwJSwgNTAlKSIgZD0iTTIwMS4yOTUgMTI5Ljc4MmE2Ni41IDY2LjUgMCAwMC0uMTYtMS43MzMiLz48cGF0aCBzdHJva2U9ImhzbCgyMzUsIDEwMCUsIDUwJSkiIGQ9Ik0yMDEuMzc2IDEzMC45NGE2Ni41IDY2LjUgMCAwMC0uMTMtMS43MzYiLz48cGF0aCBzdHJva2U9ImhzbCgyMzYsIDEwMCUsIDUwJSkiIGQ9Ik0yMDEuNDM3IDEzMi4xYTY2LjUgNjYuNSAwIDAwLS4wOTktMS43MzkiLz48cGF0aCBzdHJva2U9ImhzbCgyMzcsIDEwMCUsIDUwJSkiIGQ9Ik0yMDEuNDc3IDEzMy4yNmE2Ni41IDY2LjUgMCAwMC0uMDY4LTEuNzQiLz48cGF0aCBzdHJva2U9ImhzbCgyMzgsIDEwMCUsIDUwJSkiIGQ9Ik0yMDEuNDk3IDEzNC40MmE2Ni41IDY2LjUgMCAwMC0uMDM4LTEuNzQiLz48cGF0aCBzdHJva2U9ImhzbCgyMzksIDEwMCUsIDUwJSkiIGQ9Ik0yMDEuNDk3IDEzNS41OGE2Ni41IDY2LjUgMCAwMC0uMDA3LTEuNzQiLz48L2c+PGNpcmNsZSBjeD0iMTM1IiBjeT0iMTM1IiByPSIxMzMiIGZpbGw9InVybCgjYSkiIGNsYXNzPSJJcm9XaGVlbFNhdHVyYXRpb24iLz48Y2lyY2xlIGN4PSIxMzUiIGN5PSIxMzUiIHI9IjEzMyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiIGNsYXNzPSJJcm9XaGVlbEJvcmRlciIvPjwvc3ZnPg=='; - - this.width = this.offsetWidth; - this.height = this.offsetHeight; - }, - mousedown: function (event) { - var cvs = this, - ctx = this.getContext('2d'); - - function update(x, y) { - var cursor = cvs.nextSibling.nextSibling; - - cursor.style.left = x + cvs.offsetLeft + 'px'; - cursor.style.top = y + cvs.offsetTop + 'px'; - } - - function mousemove(event) { - update(event.layerX, event.layerY); - } - - function mouseup(event) { - cvs.parentNode.data = { - rgb: ctx.getImageData(event.layerX, event.layerY, 1, 1).data, - cursor: [event.layerX, event.layerY] - }; - - this.removeEventListener('mousemove', mousemove); - this.removeEventListener('mouseup', mouseup); - } - - this.addEventListener('mousemove', mousemove); - this.addEventListener('mouseup', mouseup); - - update(event.layerX, event.layerY); - - cvs.nextSibling.nextSibling.hidden = false; - } - } - }, - shadow: { - component: 'div', - class: 'satus-color-picker__dim' - }, - cursor: { - component: 'div', - class: 'satus-color-picker__cursor', - attr: { - hidden: true - }, - on: { - render: function () { - var data = this.parentNode.data; - - if (data.cursor) { - this.style.left = data.cursor[0] + 'px'; - this.style.top = data.cursor[1] + 'px'; - - this.hidden = false; - } - } - } - }, - slider: { - component: 'slider', - class: 'satus-color-picker__slider', - step: .01, - on: { - render: function () { - var data = this.parentNode.data; - - function rgbToHsv(r, g, b) { - r /= 255, g /= 255, b /= 255; - - var max = Math.max(r, g, b), - min = Math.min(r, g, b); - var h, s, v = max; - - var d = max - min; - s = max == 0 ? 0 : d / max; - - if (max == min) { - h = 0; // achromatic - } else { - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - - h /= 6; - } - - return [h, s, v]; - } - - this.value = 1 - rgbToHsv(data.rgb[0], data.rgb[1], data.rgb[2])[2]; - }, - change: function () { - this.previousSibling.previousSibling.style.opacity = this.value; - } - } - }, - actions: { - component: 'section', - class: 'satus-color-picker__actions', - - reset: { - component: 'button', - text: 'reset', - - on: { - click: function () { - var modal = this.parentNode.parentNode.parentNode, - component = modal.parentComponent; - - component.data = component.skeleton.value; - - if (component.storage) { - satus.storage.set(component.storage, false); - } - - var data = component.skeleton.value || { - rgb: [0, 0, 0] - }; - - component.valueElement.style.backgroundColor = 'rgb(' + data.rgb[0] + ',' + data.rgb[1] + ',' + data.rgb[2] + ')'; - - modal.close(); - - component.colorValue = data; - - component.dispatchEvent(new CustomEvent('change')); - } - } - }, - cancel: { - component: 'button', - text: 'cancel', - - on: { - click: function () { - var modal = this.parentNode.parentNode.parentNode; - - modal.close(); - } - } - }, - ok: { - component: 'button', - text: 'OK', - - on: { - click: function () { - var modal = this.parentNode.parentNode.parentNode, - data = this.parentNode.parentNode.data; - - function rgbToHsv(r, g, b) { - r /= 255, g /= 255, b /= 255; - - var max = Math.max(r, g, b), - min = Math.min(r, g, b); - var h, s, v = max; - - var d = max - min; - s = max == 0 ? 0 : d / max; - - if (max == min) { - h = 0; // achromatic - } else { - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - - h /= 6; - } - - return [h, s, v]; - } - - function hsvToRgb(h, s, v) { - var r, g, b; - - var i = Math.floor(h * 6); - var f = h * 6 - i; - var p = v * (1 - s); - var q = v * (1 - f * s); - var t = v * (1 - (1 - f) * s); - - switch (i % 6) { - case 0: - r = v, g = t, b = p; - break; - case 1: - r = q, g = v, b = p; - break; - case 2: - r = p, g = v, b = t; - break; - case 3: - r = p, g = q, b = v; - break; - case 4: - r = t, g = p, b = v; - break; - case 5: - r = v, g = p, b = q; - break; - } - - return [r * 255, g * 255, b * 255]; - } - - var hsv = rgbToHsv(data.rgb[0], data.rgb[1], data.rgb[2]); - - hsv[2] = 1 - this.parentNode.previousSibling.value; - - data.rgb = hsvToRgb(hsv[0], hsv[1], hsv[2]); - - modal.parentComponent.valueElement.style.backgroundColor = 'rgb(' + data.rgb[0] + ',' + data.rgb[1] + ',' + data.rgb[2] + ')'; - - if (modal.parentComponent.storage) { - satus.storage.set(modal.parentComponent.storage, data); - } - - modal.parentComponent.colorValue = data; - - modal.close(); - - modal.parentComponent.dispatchEvent(new CustomEvent('change')); - } - } - } - } - }); - }); - - component.appendChild(component_value); - - return component; -}; -/*-------------------------------------------------------------- ->>> TABS ---------------------------------------------------------------*/ - -satus.components.tabs = function (skeleton) { - var component = document.createElement('div'), - selection = document.createElement('div'); - - selection.className = 'satus-tabs__selection'; - - component.appendChild(selection); - - component.selection = selection; - - for (var i = 0, l = skeleton.items.length; i < l; i++) { - var item = skeleton.items[i], - button = document.createElement('button'); - - button.className = 'satus-tabs__button'; - button.value = item; - - satus.text(button, item); - - button.addEventListener('click', function () { - var component = this.parentNode; - - component.value = this.value; - - component.selection.style.left = this.offsetLeft + 'px'; - - component.dispatchEvent(new CustomEvent('change')); - }); - - if (skeleton.value === item) { - selection.style.left = i * 50 + '%'; - } - - component.appendChild(button); - } - - return component; -}; -/*-------------------------------------------------------------- ->>> RADIO ---------------------------------------------------------------*/ - -satus.components.radio = function (skeleton) { - var component = document.createElement('label'), - content = document.createElement('span'), - radio = document.createElement('input'), - value = satus.storage.get(skeleton.group); - - component.inner = content; - - radio.type = 'radio'; - - if (skeleton.group) { - radio.name = skeleton.group; - } - - if (skeleton.value) { - radio.value = skeleton.value; - } - - if (satus.isset(value)) { - radio.checked = value === skeleton.value; - } - - radio.addEventListener('change', function () { - satus.storage.set(this.name, this.value); - }); - - component.appendChild(content); - component.appendChild(radio); - - return component; -}; -/*-------------------------------------------------------------- ->>> LIST ---------------------------------------------------------------*/ - -satus.components.list = function (skeleton) { - var ul = document.createElement('ul'); - - for (var i = 0, l = skeleton.items.length; i < l; i++) { - var li = document.createElement('li'), - item = skeleton.items[i]; - - li.className = 'satus-list__item'; - - for (var j = 0, k = item.length; j < k; j++) { - var child = item[j]; - - if (typeof child === 'string') { - var span = document.createElement('span'); - - span.textContent = satus.locale.get(child); - - li.appendChild(span); - } else { - satus.render(child, li); - } - } - - ul.appendChild(li); - } - - return ul; -}; -/*-------------------------------------------------------------- ->>> MODAL ---------------------------------------------------------------*/ - -satus.components.modal = function (skeleton) { - var component = document.createElement('div'), - scrim = document.createElement('div'), - surface = document.createElement('div'); - - scrim.className = 'satus-modal__scrim'; - surface.className = 'satus-modal__surface'; - - component.close = function () { - var component = this, - component_surface = this.children[1]; - - this.classList.add('satus-modal--closing'); - - setTimeout(function () { - component.remove(); - - component.dispatchEvent(new CustomEvent('close')); - }, satus.getAnimationDuration(component_surface)); - }; - - scrim.addEventListener('click', function () { - this.parentNode.close(); - }); - - component.appendChild(scrim); - component.appendChild(surface); - - component.inner = surface; - - return component; -}; -/*-------------------------------------------------------------- ->>> SWITCH ---------------------------------------------------------------*/ - -satus.components.switch = function (skeleton) { - var component = document.createElement('button'), - component_content = document.createElement('span'), - component_thumb = document.createElement('i'), - value = satus.storage.get(skeleton.storage); - - component.inner = component_content; - - if (satus.isset(value)) { - component.dataset.value = value; - } else if (skeleton.hasOwnProperty('value')) { - component.dataset.value = skeleton.value; - } - - component.addEventListener('click', function () { - if (this.dataset.value === 'true') { - this.dataset.value = 'false'; - } else { - this.dataset.value = 'true'; - } - - this.change(this.dataset.value === 'true'); - }); - - component.appendChild(component_content); - component.appendChild(component_thumb); - - return component; -}; -/*-------------------------------------------------------------- ->>> SLIDER: ----------------------------------------------------------------- -# ---------------------------------------------------------------*/ - -satus.components.slider = function (skeleton) { - var component = document.createElement('div'), - container = document.createElement('div'), - track_container = document.createElement('div'), - track = document.createElement('div'), - ring = document.createElement('div'), - thumb = document.createElement('div'), - range = document.createElement('input'), - value = satus.storage.get(skeleton.storage); - - container.className = 'satus-slider__container'; - track_container.className = 'satus-slider__track-container'; - track.className = 'satus-slider__track'; - ring.className = 'satus-slider__ring'; - thumb.className = 'satus-slider__thumb'; - - range.type = 'range'; - range.step = skeleton.step || 1; - range.max = skeleton.max || 1; - range.min = skeleton.min || 0; - - component.input = range; - - if (satus.isset(value)) { - range.value = value; - } else if (skeleton.hasOwnProperty('value')) { - range.value = skeleton.value; - } else { - range.value = 0; - } - - component.appendChild(container); - track_container.appendChild(track); - container.appendChild(track_container); - track.appendChild(ring); - track.appendChild(thumb); - component.appendChild(range); - - component.update = function () { - var track = this.querySelector('.satus-slider__track'), - thumb = this.querySelector('.satus-slider__thumb'), - min = Number(this.input.min) || 0, - max = Number(this.input.max) || 1, - step = Number(this.input.step) || 1, - value = Number(this.input.value) || 0, - offset = (value - min) / (max - min) * 100; - - track.style.width = 'calc(' + offset + '% - ' + Math.floor(offset * 12 / 100) + 'px)'; - - thumb.dataset.value = this.input.value; - }; - - Object.defineProperty(component, 'value', { - get: function () { - return this.input.value; - }, - set: function (value) { - this.input.value = value; - - this.update(); - - satus.storage.set(this.skeleton.storage, Number(value)); - - this.dispatchEvent(new CustomEvent('change')); - } - }); - - range.addEventListener('input', function () { - var component = this.parentNode; - - console.log(this.value); - - component.value = this.value; - }); - - component.update(); - - return component; -}; -/*-------------------------------------------------------------- ->>> SHORTCUT ---------------------------------------------------------------*/ - -satus.components.shortcut = function (skeleton) { - var component = document.createElement('button'), - value = document.createElement('div'); - - component.className = 'satus-button'; - value.className = 'satus-shortcut__value'; - - component.update = function () { - var object = satus.storage.get(this.storage) || this.skeleton.value || {}, - array = []; - - if (object.shift) { - array.push('Shift'); - } - - if (object.ctrl) { - array.push('Ctrl'); - } - - if (object.alt) { - array.push('Alt'); - } - - if (typeof object.keys === 'object') { - for (var key in object.keys) { - var char = object.keys[key].key || object.keys[key].code; - - if (key === 32) { - char = 'space'; - } - - array.push(char); - } - } - - this.valueElement.textContent = array.join(' + '); - }; - - component.render = function () { - var self = this, - children = this.primary.children; - - satus.empty(this.primary); - - function createElement(name) { - var element = document.createElement('div'); - - element.className = 'satus-shortcut__' + name; - - self.primary.appendChild(element); - - return element; - } - - if (this.data.alt) { - createElement('key').textContent = 'Alt'; - } - - if (this.data.ctrl) { - if (children.length && children[children.length - 1].className.indexOf('key') !== -1) { - createElement('plus'); - } - - createElement('key').textContent = 'Ctrl'; - } - - if (this.data.shift) { - if (children.length && children[children.length - 1].className.indexOf('key') !== -1) { - createElement('plus'); - } - - createElement('key').textContent = 'Shift'; - } - - for (var code in this.data.keys) { - if (children.length && children[children.length - 1].className.indexOf('key') !== -1) { - createElement('plus'); - } - - createElement('key').textContent = this.data.keys[code].key.toUpperCase(); - } - - if (this.data.wheel) { - if (children.length && children[children.length - 1].className.indexOf('key') !== -1) { - createElement('plus'); - } - - var mouse = createElement('mouse'), - div = document.createElement('div'); - - mouse.appendChild(div); - - mouse.className += ' ' + (this.data.wheel > 0); - } - }; - - component.valueElement = value; - - component.data = satus.storage.get(skeleton.storage) || skeleton.value || { - alt: false, - ctrl: false, - shift: false, - keys: {}, - wheel: 0 - }; - - component.appendChild(value); - - component.keydown = function (event) { - event.preventDefault(); - event.stopPropagation(); - - component.data = { - alt: event.altKey, - ctrl: event.ctrlKey, - shift: event.shiftKey, - keys: {} - }; - - component.data.keys[event.keyCode] = { - code: event.code, - key: event.key - }; - - component.data.wheel = 0; - - component.render(); - - return false; - }; - - component.mousewheel = function (event) { - event.preventDefault(); - event.stopPropagation(); - - component.data.wheel = event.deltaY; - - component.render(); - - return false; - }; - - component.addEventListener('click', function () { - satus.render({ - component: 'modal', - on: { - close: function () { - window.removeEventListener('keydown', this.keydown); - window.removeEventListener('mousewheel', this.mousewheel); - } - }, - - primary: { - component: 'div', - class: 'satus-shortcut__primary', - on: { - render: function () { - component.primary = this; - - component.render(); - } - } - }, - actions: { - component: 'div', - class: 'satus-shortcut__actions', - - reset: { - component: 'button', - text: 'reset', - on: { - click: function () { - component.data = component.skeleton.value; - - component.update(); - - satus.storage.set(component.storage, false); - - this.parentNode.parentNode.parentNode.close(); - - window.removeEventListener('keydown', this.keydown); - window.removeEventListener('mousewheel', this.mousewheel); - } - } - }, - cancel: { - component: 'button', - text: 'cancel', - on: { - click: function () { - component.data = satus.storage.get(skeleton.storage) || component.skeleton.value; - - component.update(); - - this.parentNode.parentNode.parentNode.close(); - - window.removeEventListener('keydown', this.keydown); - window.removeEventListener('mousewheel', this.mousewheel); - } - } - }, - save: { - component: 'button', - text: 'save', - on: { - click: function () { - satus.storage.set(component.storage, component.data); - - component.update(); - - this.parentNode.parentNode.parentNode.close(); - - window.removeEventListener('keydown', this.keydown); - window.removeEventListener('mousewheel', this.mousewheel); - } - } - } - } - }); - - window.addEventListener('keydown', this.keydown); - window.addEventListener('mousewheel', this.mousewheel); - }); - - component.addEventListener('render', component.update); - - return component; -}; -/*-------------------------------------------------------------- ->>> BASE ---------------------------------------------------------------*/ - -satus.components.base = function (skeleton) { - var component = document.createElement('div'); - - component.base = component; - - return component; -}; -/*-------------------------------------------------------------- ->>> TEXT FIELD ---------------------------------------------------------------*/ - -satus.components.textField = function (skeleton) { - var component = document.createElement('div'), - pre = document.createElement('pre'), - input = document.createElement('textarea'), - hidden_text = document.createElement('span'), - text = document.createElement('span'), - selection = document.createElement('div'), - cursor = document.createElement('div'), - value = satus.storage.get(skeleton.storage); - - input.className = 'satus-text-field__input'; - pre.className = 'satus-text-field__pre'; - hidden_text.className = 'satus-text-field__hidden-text'; - text.className = 'satus-text-field__text'; - selection.className = 'satus-text-field__selection'; - cursor.className = 'satus-text-field__cursor'; - - component.inputElement = input; - component.textElement = text; - component.languages = { - regex: function (component) { - var regex_token = /\[\^?]?(?:[^\\\]]+|\\[\S\s]?)*]?|\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9][0-9]*|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)|\((?:\?[:=!]?)?|(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??|[^.?*+^${[()|\\]+|./g, - char_class_token = /[^\\-]+|-|\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)/g, - char_class_parts = /^(\[\^?)(]?(?:[^\\\]]+|\\[\S\s]?)*)(]?)$/, - quantifier = /^(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??$/, - matches = component.inputElement.value.match(regex_token); - - function create(type, string) { - var span = document.createElement('span'); - - span.className = type; - span.textContent = string; - - component.textElement.appendChild(span); - } - - for (var i = 0, l = matches.length; i < l; i++) { - var match = matches[i]; - - if (match[0] === '[') { - create('character-class', match); - } else if (match[0] === '(') { - create('group', match); - } else if (match[0] === ')') { - create('group', match); - } else if (match[0] === '\\' || match === '^') { - create('anchor', match); - } else if (quantifier.test(match)) { - create('quantifier', match); - } else if (match === '|' || match === '.') { - create('metasequence', match); - } else { - create('text', match); - } - } - } - }; - component._syntax = skeleton.syntax; - - Object.defineProperty(component, 'value', { - get: function () { - return this.inputElement.value; - }, - set: function (value) { - var input = this.inputElement; - - input.value = value; - - input.updateValue(); - input.updateCursor(); - } - }); - - Object.defineProperty(component, 'syntax', { - get: function () { - return this._syntax; - }, - set: function (value) { - var input = this.inputElement; - - this._syntax = value; - - input.updateValue(); - input.updateCursor(); - } - }); - - input.rows = skeleton.rows || 1; - input.autocapitalize = 'none'; - input.autocomplete = 'off'; - input.autocorrect = 'off'; - input.spellcheck = false; - input.autofocus = true; - input.textElement = text; - input.hiddenTextElement = hidden_text; - input.selectionElement = selection; - input.cursorElement = cursor; - - input.updateValue = function () { - var component = this.parentNode.parentNode; - - for (var i = this.textElement.childNodes.length - 1; i > -1; i--) { - this.textElement.childNodes[i].remove(); - } - - if (this.value.length > 0) { - if (component.languages[component._syntax]) { - component.languages[component._syntax](component); - } else { - this.textElement.textContent = this.value; - } - } - - component.dispatchEvent(new Event('change')); - }; - - input.updateCursor = function () { - var cursor = this.cursorElement, - selection = this.selectionElement, - hidden_text = this.hiddenTextElement, - start = this.selectionStart, - end = this.selectionEnd; - - cursor.style.animation = 'none'; - - if (start === end) { - selection.setAttribute('disabled', ''); - } else { - selection.removeAttribute('disabled'); - - hidden_text.textContent = this.value.substring(0, start); - - selection.style.left = hidden_text.offsetWidth - this.scrollLeft + 'px'; - - hidden_text.textContent = this.value.substring(start, end); - - selection.style.width = hidden_text.offsetWidth + 'px'; - } - - if (this.selectionDirection === 'forward') { - hidden_text.textContent = this.value.substring(0, end); - } else { - hidden_text.textContent = this.value.substring(0, start); - } - - cursor.style.left = hidden_text.offsetWidth - this.scrollLeft + 'px'; - - cursor.style.animation = ''; - - hidden_text.textContent = ''; - }; - - input.addEventListener('keydown', function () { - var self = this; - - setTimeout(function () { - var component = self.parentNode.parentNode; - - if (component.skeleton && component.skeleton.storage) { - satus.storage.set(component.skeleton.storage, self.value); - } - - self.updateValue(); - self.updateCursor(); - }); - }); - - input.addEventListener('scroll', function (event) { - this.textElement.style.left = -this.scrollLeft + 'px'; - }); - - document.addEventListener('selectionchange', function () { - input.updateCursor(); - }); - - selection.setAttribute('disabled', ''); - - pre.appendChild(input); - pre.appendChild(hidden_text); - pre.appendChild(text); - pre.appendChild(selection); - pre.appendChild(cursor); - component.appendChild(pre); - - if (satus.isset(value)) { - component.value = value; - } else if (skeleton.hasOwnProperty('value')) { - if (typeof skeleton.value === 'function') { - input.value = skeleton.value(); - } else if (skeleton.value) { - input.value = skeleton.value; - } - } - - component.addEventListener('render', function () { - this.inputElement.updateValue(); - this.inputElement.updateCursor(); - }); - - return component; -}; -/*-------------------------------------------------------------- ->>> ALERT ---------------------------------------------------------------*/ - -satus.components.alert = function (skeleton) { - var component = document.createElement('div'); - - return component; -}; -/*-------------------------------------------------------------- ->>> LAYERS ---------------------------------------------------------------*/ - -satus.components.layers = function (skeleton) { - var component = document.createElement('div'); - - component.path = [skeleton]; - - component.back = function () { - if (this.path.length > 1) { - this.path.pop(); - - this.open(); - } - }; - - component.open = function (skeleton) { - var layer = document.createElement('div'); - - if (skeleton) { - this.path.push(skeleton); - } else { - skeleton = this.path[this.path.length - 1]; - } - - layer.className = 'satus-layer'; - - layer.skeleton = skeleton; - layer.base = this.base; - - satus.render(skeleton, layer, skeleton.component === 'layers'); - - satus.empty(this); - - this.appendChild(layer); - - this.dispatchEvent(new Event('open')); - }; - - component.update = function () { - var layer = this.querySelector('.satus-layer'); - - satus.empty(layer); - - satus.render(layer.skeleton, layer); - }; - - component.render_children = false; - - component.addEventListener('render', function () { - this.open(); - }); - - return component; -}; -/*-------------------------------------------------------------- ->>> INPUT ---------------------------------------------------------------*/ - -satus.components.input = function (skeleton) { - var component = document.createElement('input'); - - if (skeleton.attr) { - var key = skeleton.attr.name || skeleton.storage, - value; - - if (satus.isset(satus.storage.get(key))) { - value = satus.storage.get(key); - } else { - value = skeleton.value; - } - - if (skeleton.attr.type === 'radio') { - component.checked = value === skeleton.attr.value || skeleton.value; - } else if (satus.isset(value)) { - component.value = value; - } - - component.addEventListener('change', function () { - var key = this.skeleton.attr.name || this.skeleton.storage; - - satus.storage.set(key, this.value); - }); - } - - return component; -}; -/*-------------------------------------------------------------- ->>> SELECT ---------------------------------------------------------------*/ - -satus.components.select = function (skeleton) { - var component = document.createElement('div'), - component_label = document.createElement('span'), - component_value = document.createElement('span'), - select = document.createElement('select'); - - component_value.className = 'satus-select__value'; - - for (var i = 0, l = skeleton.options.length; i < l; i++) { - var option = document.createElement('option'); - - option.value = skeleton.options[i].value; - - satus.text(option, skeleton.options[i].text); - - select.appendChild(option); - } - - component.selectElement = select; - select.valueElement = component_value; - - select.addEventListener('change', function () { - satus.empty(this.valueElement); - - satus.text(this.valueElement, this.options[this.selectedIndex].text); - - this.parentNode.change(this.value); - }); - - component.appendChild(component_label); - component.appendChild(component_value); - component.appendChild(select); - - component.addEventListener('render', function () { - var select = this.selectElement, - value = satus.storage.get(this.storage) || this.skeleton.options[0].value; - - select.value = value; - - satus.text(select.valueElement, select.options[select.selectedIndex].text); - }); - - component.inner = component_label; - - return component; -}; -/*-------------------------------------------------------------- ->>> USER ---------------------------------------------------------------*/ - -satus.user = function () { - /*-------------------------------------------------------------- - 1.0 VARIABLES - --------------------------------------------------------------*/ - - var user_agent = navigator.userAgent, - random_cookie = 'ta{t`nX6cMXK,Wsc', - video = document.createElement('video'), - video_formats = { - ogg: 'video/ogg; codecs="theora"', - h264: 'video/mp4; codecs="avc1.42E01E"', - webm: 'video/webm; codecs="vp8, vorbis"', - vp9: 'video/webm; codecs="vp9"', - hls: 'application/x-mpegURL; codecs="avc1.42E01E"' - }, - audio = document.createElement('audio'), - audio_formats = { - mp3: 'audio/mpeg', - mp4: 'audio/mp4', - aif: 'audio/x-aiff' - }, - cvs = document.createElement('canvas'), - ctx = cvs.getContext('webgl'), - data = { - browser: { - audio: null, - cookies: null, - flash: null, - java: null, - languages: null, - name: null, - platform: null, - version: null, - video: null, - webgl: null - }, - os: { - name: null, - type: null - }, - device: { - connection: { - type: null, - speed: null - }, - cores: null, - gpu: null, - max_touch_points: null, - ram: null, - screen: null, - touch: null - } - }; - - - /*-------------------------------------------------------------- - 2.0 SOFTWARE - --------------------------------------------------------------*/ - - /*-------------------------------------------------------------- - 2.1.0 OS - --------------------------------------------------------------*/ - - /*-------------------------------------------------------------- - 2.1.1 NAME - --------------------------------------------------------------*/ - - if (navigator.appVersion.indexOf('Win') !== -1) { - if (navigator.appVersion.match(/(Windows 10.0|Windows NT 10.0)/)) { - data.os.name = 'Windows 10'; - } else if (navigator.appVersion.match(/(Windows 8.1|Windows NT 6.3)/)) { - data.os.name = 'Windows 8.1'; - } else if (navigator.appVersion.match(/(Windows 8|Windows NT 6.2)/)) { - data.os.name = 'Windows 8'; - } else if (navigator.appVersion.match(/(Windows 7|Windows NT 6.1)/)) { - data.os.name = 'Windows 7'; - } else if (navigator.appVersion.match(/(Windows NT 6.0)/)) { - data.os.name = 'Windows Vista'; - } else if (navigator.appVersion.match(/(Windows NT 5.1|Windows XP)/)) { - data.os.name = 'Windows XP'; - } else { - data.os.name = 'Windows'; - } - } else if (navigator.appVersion.indexOf('(iPhone|iPad|iPod)') !== -1) { - data.os.name = 'iOS'; - } else if (navigator.appVersion.indexOf('Mac') !== -1) { - data.os.name = 'macOS'; - } else if (navigator.appVersion.indexOf('Android') !== -1) { - data.os.name = 'Android'; - } else if (navigator.appVersion.indexOf('OpenBSD') !== -1) { - data.os.name = 'OpenBSD'; - } else if (navigator.appVersion.indexOf('SunOS') !== -1) { - data.os.name = 'SunOS'; - } else if (navigator.appVersion.indexOf('Linux') !== -1) { - data.os.name = 'Linux'; - } else if (navigator.appVersion.indexOf('X11') !== -1) { - data.os.name = 'UNIX'; - } - - /*-------------------------------------------------------------- - 2.1.2 TYPE - --------------------------------------------------------------*/ - - if (navigator.appVersion.match(/(Win64|x64|x86_64|WOW64)/)) { - data.os.type = '64-bit'; - } else { - data.os.type = '32-bit'; - } - - - /*-------------------------------------------------------------- - 2.2.0 BROWSER - --------------------------------------------------------------*/ - - /*-------------------------------------------------------------- - 2.2.1 NAME - --------------------------------------------------------------*/ - - if (user_agent.indexOf('Opera') !== -1) { - data.browser.name = 'Opera'; - } else if (user_agent.indexOf('Vivaldi') !== -1) { - data.browser.name = 'Vivaldi'; - } else if (user_agent.indexOf('Edge') !== -1) { - data.browser.name = 'Edge'; - } else if (user_agent.indexOf('Chrome') !== -1) { - data.browser.name = 'Chrome'; - } else if (user_agent.indexOf('Safari') !== -1) { - data.browser.name = 'Safari'; - } else if (user_agent.indexOf('Firefox') !== -1) { - data.browser.name = 'Firefox'; - } else if (user_agent.indexOf('MSIE') !== -1) { - data.browser.name = 'IE'; - } - - - /*-------------------------------------------------------------- - 2.2.2 VERSION - --------------------------------------------------------------*/ - - var browser_version = user_agent.match(new RegExp(data.browser.name + '/([0-9.]+)')); - - if (browser_version[1]) { - data.browser.version = browser_version[1]; - } - - - /*-------------------------------------------------------------- - 2.2.3 PLATFORM - --------------------------------------------------------------*/ - - data.browser.platform = navigator.platform || null; - - - /*-------------------------------------------------------------- - 2.2.4 LANGUAGES - --------------------------------------------------------------*/ - - data.browser.languages = navigator.languages || null; - - - /*-------------------------------------------------------------- - 2.2.5 COOKIES - --------------------------------------------------------------*/ - - if (document.cookie) { - document.cookie = random_cookie; - - if (document.cookie.indexOf(random_cookie) !== -1) { - data.browser.cookies = true; - } - } - - - /*-------------------------------------------------------------- - 2.2.6 FLASH - --------------------------------------------------------------*/ - - try { - if (new ActiveXObject('ShockwaveFlash.ShockwaveFlash')) { - data.browser.flash = true; - } - } catch (e) { - if (navigator.mimeTypes['application/x-shockwave-flash']) { - data.browser.flash = true; - } - } - - - /*-------------------------------------------------------------- - 2.2.7 JAVA - --------------------------------------------------------------*/ - - if (typeof navigator.javaEnabled === 'function' && navigator.javaEnabled()) { - data.browser.java = true; - } - - - /*-------------------------------------------------------------- - 2.2.8 VIDEO FORMATS - --------------------------------------------------------------*/ - - if (typeof video.canPlayType === 'function') { - data.browser.video = {}; - - for (var i in video_formats) { - var can_play_type = video.canPlayType(video_formats[i]); - - if (can_play_type === '') { - data.browser.video[i] = false; - } else { - data.browser.video[i] = can_play_type; - } - } - } - - - /*-------------------------------------------------------------- - 2.2.9 AUDIO FORMATS - --------------------------------------------------------------*/ - - if (typeof audio.canPlayType === 'function') { - data.browser.audio = {}; - - for (var i in audio_formats) { - var can_play_type = audio.canPlayType(audio_formats[i]); - - if (can_play_type == '') { - data.browser.audio[i] = false; - } else { - data.browser.audio[i] = can_play_type; - } - } - } - - - /*-------------------------------------------------------------- - 2.2.10 WEBGL - --------------------------------------------------------------*/ - - if (ctx && ctx instanceof WebGLRenderingContext) { - data.browser.webgl = true; - } - - - /*-------------------------------------------------------------- - 3.0 HARDWARE - --------------------------------------------------------------*/ - - /*-------------------------------------------------------------- - 3.1 SCREEN - --------------------------------------------------------------*/ - - if (screen) { - data.device.screen = screen.width + 'x' + screen.height; - } - - - /*-------------------------------------------------------------- - 3.2 RAM - --------------------------------------------------------------*/ - - if ('deviceMemory' in navigator) { - data.device.ram = navigator.deviceMemory + ' GB'; - } - - - /*-------------------------------------------------------------- - 3.3 GPU - --------------------------------------------------------------*/ - - if ( - ctx && - ctx instanceof WebGLRenderingContext && - 'getParameter' in ctx && - 'getExtension' in ctx - ) { - var info = ctx.getExtension('WEBGL_debug_renderer_info'); - - if (info) { - data.device.gpu = ctx.getParameter(info.UNMASKED_RENDERER_WEBGL); - } - } - - - /*-------------------------------------------------------------- - 3.4 CORES - --------------------------------------------------------------*/ - - if (navigator.hardwareConcurrency) { - data.device.cores = navigator.hardwareConcurrency; - } - - - /*-------------------------------------------------------------- - 3.5 TOUCH - --------------------------------------------------------------*/ - - if ( - window.hasOwnProperty('ontouchstart') || - window.DocumentTouch && document instanceof window.DocumentTouch || - navigator.maxTouchPoints > 0 || - window.navigator.msMaxTouchPoints > 0 - ) { - data.device.touch = true; - data.device.max_touch_points = navigator.maxTouchPoints; - } - - - /*-------------------------------------------------------------- - 3.6 CONNECTION - --------------------------------------------------------------*/ - - if (typeof navigator.connection === 'object') { - data.device.connection.type = navigator.connection.effectiveType || null; - - if (navigator.connection.downlink) { - data.device.connection.speed = navigator.connection.downlink + ' Mbps'; - } - } - - - /*-------------------------------------------------------------- - 4.0 CLEARING - --------------------------------------------------------------*/ - - video.remove(); - audio.remove(); - cvs.remove(); - - - return data; -}; -/*-------------------------------------------------------------- ->>> EXTENSION STORAGE ---------------------------------------------------------------*/ -/*-------------------------------------------------------------- ->>> PLUVIAM ---------------------------------------------------------------*/ - -satus.events.add('render', function (component, skeleton) { - if (skeleton.pluviam === true) { - function createPluviam(event) { - var pluviam = document.createElement('span'), - rect = this.getBoundingClientRect(), - x = event.clientX - rect.left, - y = event.clientY - rect.top, - diameter = Math.sqrt(Math.pow(rect.width * 2, 2) + Math.pow(rect.height * 2, 2)); - - pluviam.className = 'satus-pluviam'; - - pluviam.style.left = x - diameter / 2 + 'px'; - pluviam.style.top = y - diameter / 2 + 'px'; - pluviam.style.width = diameter + 'px'; - pluviam.style.height = diameter + 'px'; - - this.appendChild(pluviam); - - setTimeout(function () { - pluviam.remove(); - }, 1000); - } - - component.addEventListener('mousedown', createPluviam); - component.addEventListener('mouseover', createPluviam); - } -}); \ No newline at end of file