1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-09-14 19:32:10 +02:00

Compare commits

...

75 Commits
1.3.2 ... 1.4

Author SHA1 Message Date
aa2c60f7e9 Move cookie import code to ExportManager 2016-09-20 17:15:34 +02:00
f7dc200684 Kill process instead of Environment.FailFast if possible 2016-09-20 17:11:36 +02:00
ad306c56c7 Move log file to storage path 2016-09-20 16:58:00 +02:00
86aba1eb52 Update all exception handlers 2016-09-20 16:55:51 +02:00
826f1aba7a Tweak exception handling in Reporter (use Environment.FailFast and change log button title) 2016-09-20 16:51:29 +02:00
8abf4364c6 Replace calls to Program.Log 2016-09-20 16:39:31 +02:00
4c45d91d4e Move logging to Reporter and make a static instance of it in Program 2016-09-20 16:38:15 +02:00
3176b6cb8f Create a Reporter class with improved HandleException code 2016-09-20 16:34:56 +02:00
27971e09cd Add new Control related functionality to FormMessage 2016-09-20 16:31:53 +02:00
bf95ae00de Tweak the message for missing write permission 2016-09-20 16:10:46 +02:00
0dbfa7e101 Improve reliability of directory write perm checking 2016-09-20 16:00:41 +02:00
85d09c4b5e Add a FormMessage class for custom message boxes 2016-09-20 07:47:16 +02:00
4f9bc40476 Update cache clearing for CEF 53 and clear old cache files on first startup 2016-09-19 14:03:37 +02:00
757ccbf9d3 Switch locale to English and add spell check setting
Closes #62
2016-09-19 13:33:44 +02:00
4cf9730130 Make sure the config is not loaded before old process exits when restarting 2016-09-19 13:24:23 +02:00
1dd0d70ab9 Reorganize Program.LogFile from property to readonly field 2016-09-19 13:08:27 +02:00
340eaece0f Update CefSharp to 53 and update the readme 2016-09-19 00:12:48 +02:00
c151e7cd37 Remove everything TweetDick related 2016-09-18 23:24:11 +02:00
ca0baae832 Release 1.3.3 2016-09-18 22:23:48 +02:00
478e6ed8df Move config loading and migration execution to an earlier point 2016-09-18 22:19:02 +02:00
7388eb07ca Increase process close timeouts to 20 seconds from 10 2016-09-18 21:49:41 +02:00
c38d507e50 Hopefully fix an occasional crash when importing session and restarting 2016-09-18 21:48:40 +02:00
5aee087a57 Add a Program Files warning if not running as administrator 2016-09-18 21:17:30 +02:00
0cda3702ea Change notification scroll trigger cursor position for windows without side borders 2016-09-18 21:08:09 +02:00
ce55226d0c Add error handling to logging 2016-09-18 20:50:43 +02:00
0bab0a9963 Update reply-account plugin metadata and default config warning 2016-09-18 20:29:49 +02:00
34955b7083 Rewrite Plugin default config handling and config error reporting 2016-09-18 20:29:31 +02:00
ba6ce072ac Add support for a -datafolder command line argument 2016-09-18 19:42:00 +02:00
f39fd00697 Add a TweetDick warning and migration prompt 2016-09-18 19:41:37 +02:00
58fc1be1d5 Add CefSharp version to NuGet instructions 2016-09-12 14:29:48 +02:00
1fdf9bffb6 Disable global context menu items when in textarea or text selection 2016-09-07 21:47:31 +02:00
2ad179ef8e Rename configuration file in reply-account plugin 2016-09-07 15:03:06 +02:00
d42cc5b762 Remove .js file block in Plugin folders 2016-09-07 15:01:08 +02:00
403658f622 Add config file to reply-account plugin metadata 2016-09-07 14:43:17 +02:00
6ca35685db Add button for easy Plugin config file access 2016-09-07 14:42:21 +02:00
bfc6822f69 Fix Plugins window title 2016-09-07 14:20:35 +02:00
b0386937d7 Remove lnk updater from the TweetDeck migration system 2016-09-05 21:25:25 +02:00
9436540b2f Add CultureInfo.CurrentCulture to time in logger 2016-09-05 20:45:39 +02:00
45b0ece342 Update Plugin sorting and design (separator, colors) 2016-09-05 20:44:58 +02:00
5c147d3648 Fix missing and unfocused scrollbar in Plugins window 2016-09-05 20:44:07 +02:00
8fa68c428f Add 'Open (quoted) tweet in browser' context menu items and move them down 2016-09-05 16:17:23 +02:00
e2be90191e Standardize context menu items using Chrome's style 2016-09-05 14:30:07 +02:00
339da2f1a9 Add unsupported system notification
Closes #58
2016-09-04 20:30:35 +02:00
b2cc5d50bd Address code analysis issues and fix unused parameter in CombinedFileStream.WriteToFile 2016-09-04 19:32:33 +02:00
f38b188046 Add a safety net to plugin file export in case the path is too long 2016-09-04 18:10:50 +02:00
9e45628e87 Rename 'Export/Import Settings' to Profile and add Plugin exporting 2016-09-04 16:58:03 +02:00
bf76398627 Optimize icon loading and size in Forms, fix Plugins Form title inconsistency 2016-09-04 15:32:00 +02:00
81d5728964 Add scrollbars to Edit CSS window 2016-09-04 13:57:38 +02:00
d76027558b Add a custom alert function with customizable icon and no text length limit 2016-09-04 13:19:52 +02:00
1450cc24a3 Reorganize global context menu items into a sub-menu 2016-09-04 13:10:32 +02:00
f41523c1b2 Remove redundant 'using' directives 2016-09-04 04:53:37 +02:00
4019463e68 Fix occasional incorrect location of child windows 2016-09-04 04:52:59 +02:00
5e2e239f5e Force Reload All button in Plugins window to trigger the event even without changes 2016-09-04 04:44:08 +02:00
bc7856b6c0 Tweak wording in reply-account configuration file 2016-09-04 04:39:19 +02:00
e2bba8d9e1 Update reply-account plugin to use default config and swap event order when enabled late 2016-09-04 04:36:01 +02:00
520db2c32e Rewrite loadConfigurationFile in plugins.js to accept default config file 2016-09-04 04:33:55 +02:00
da71f2de2b Add CheckFileExists function to PluginBridge 2016-09-04 04:33:13 +02:00
6dd2c6678b Add custom exception messages to file reading in PluginBridge 2016-09-04 04:01:40 +02:00
fb3d9e6d6b Add a reply-account plugin with config 2016-09-04 04:01:00 +02:00
36473c2df9 Add a global plugins.js file with loadConfigurationFile utility function 2016-09-04 03:59:37 +02:00
81aa30b2ec Allow custom .js files in plugin folders when prefixed by 'user.' 2016-09-04 03:50:35 +02:00
85d5160782 Add plugin identifier to the object itself 2016-09-04 03:38:42 +02:00
44bf7b870e Rewrote notification mouse hook to only be active if the window is visible
Closes #57
2016-09-04 00:59:13 +02:00
44da2e6082 Add debug example notification padding for scrollbar testing 2016-09-04 00:58:47 +02:00
d576bc3972 Work around Scheduled column update delay bug in TweetDeck
Closes #53
2016-09-03 16:15:28 +02:00
dbeb4c7205 Reorganize path constants and allow the program to be portable 2016-09-02 20:59:03 +02:00
e5223a852e Fix profile picture in example tweet 2016-09-02 20:58:18 +02:00
f3884315c0 Fix visual issues with clear-columns plugin (icon in temp columns, misaligned Messages icons) 2016-09-02 20:46:54 +02:00
53cd9dc9a6 Move script files to /scripts/ folder and exclude them from Visual Studio 2016-09-02 19:05:48 +02:00
a3666a7ab2 Fix formatting in JavaScript files 2016-09-02 17:35:21 +02:00
ca4eb17308 Add a clear-columns plugins 2016-09-02 17:28:32 +02:00
b729dca2e5 Seal PluginConfig and add a method to disable official plugins from config 2016-09-02 17:25:25 +02:00
21354e675a Fix TweetDeck keyboard shortcut list alignment 2016-09-02 17:17:08 +02:00
2085ddd347 Update website in design-revert plugin to https 2016-09-02 16:41:52 +02:00
31a475861b Reformat (missing space after comma), minor code tweaks 2016-09-02 13:34:41 +02:00
79 changed files with 1675 additions and 1519 deletions

View File

@@ -4,7 +4,7 @@ using System.IO;
using System.Threading;
namespace TweetDck.Configuration{
class LockManager{
sealed class LockManager{
public Process LockingProcess { get; private set; }
private readonly string file;
@@ -90,7 +90,7 @@ namespace TweetDck.Configuration{
try{
File.Delete(file);
}catch(Exception e){
Program.Log(e.ToString());
Program.Reporter.Log(e.ToString());
result = false;
}

View File

@@ -16,7 +16,7 @@ namespace TweetDck.Configuration{
Binder = new SerializationCompatibilityHandler()
};
private const int CurrentFileVersion = 4;
private const int CurrentFileVersion = 5;
// START OF CONFIGURATION
@@ -35,6 +35,7 @@ namespace TweetDck.Configuration{
public int NotificationDurationValue { get; set; }
public bool NotificationLegacyLoad { get; set; }
public bool EnableSpellCheck { get; set; }
public bool ExpandLinksOnHover { get; set; }
public bool EnableTrayHighlight { get; set; }
@@ -116,6 +117,9 @@ namespace TweetDck.Configuration{
EnableTrayHighlight = true;
Plugins = new PluginConfig();
PluginsWindow = new WindowState();
Plugins.DisableOfficialFromConfig("clear-columns");
Plugins.DisableOfficialFromConfig("reply-account");
}
private void UpgradeFile(){
@@ -155,6 +159,12 @@ namespace TweetDck.Configuration{
++fileVersion;
}
if (fileVersion == 4){
Plugins.DisableOfficialFromConfig("clear-columns");
Plugins.DisableOfficialFromConfig("reply-account");
++fileVersion;
}
// update the version
fileVersion = CurrentFileVersion;
Save();
@@ -179,13 +189,14 @@ namespace TweetDck.Configuration{
return true;
}catch(Exception e){
Program.HandleException("Could not save the configuration file.",e);
Program.Reporter.HandleException("Configuration Error", "Could not save the configuration file.", true, e);
return false;
}
}
public static UserConfig Load(string file){
UserConfig config = null;
Exception firstException = null;
for(int attempt = 0; attempt < 2; attempt++){
try{
@@ -201,9 +212,21 @@ namespace TweetDck.Configuration{
break;
}catch(FileNotFoundException){
}catch(DirectoryNotFoundException){
break;
}catch(Exception e){
Program.HandleException("Could not open the configuration file.",e);
if (attempt == 0){
firstException = e;
Program.Reporter.Log(e.ToString());
}
else if (firstException != null){
Program.Reporter.HandleException("Configuration Error", "Could not open the backup configuration file. If you continue, you may lose your settings and list of enabled plugins.", true, e);
}
}
}
if (firstException != null && config == null){
Program.Reporter.HandleException("Configuration Error", "Could not open the configuration file.", true, firstException);
}
return config ?? new UserConfig(file);
@@ -215,12 +238,7 @@ namespace TweetDck.Configuration{
private class SerializationCompatibilityHandler : SerializationBinder{
public override Type BindToType(string assemblyName, string typeName){
#if DUCK
assemblyName = assemblyName.Replace("TweetDick", "TweetDuck");
#else
assemblyName = assemblyName.Replace("TweetDuck","TweetDick");
#endif
typeName = typeName.Replace("TweetDick", "TweetDck");
return Type.GetType(string.Format(CultureInfo.CurrentCulture, "{0}, {1}", typeName, assemblyName));
}

View File

@@ -1,3 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/></startup></configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/></startup></configuration>

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<package id="cef.redist.x64" version="3.2623.1396" targetFramework="net40-Client" />
<package id="cef.redist.x86" version="3.2623.1396" targetFramework="net40-Client" />
<package id="CefSharp.Common" version="49.0.0-pre02" targetFramework="net40-Client" />
<package id="CefSharp.WinForms" version="49.0.0-pre02" targetFramework="net40-Client" />
<package id="Microsoft.VC120.CRT.JetBrains" version="12.0.21005.2" targetFramework="net40-Client" />
<package id="cef.redist.x64" version="3.2785.1478" targetFramework="net452" />
<package id="cef.redist.x86" version="3.2785.1478" targetFramework="net452" />
<package id="CefSharp.Common" version="53.0.0-pre01" targetFramework="net452" />
<package id="CefSharp.WinForms" version="53.0.0-pre01" targetFramework="net452" />
<package id="Microsoft.VC120.CRT.JetBrains" version="12.0.21005.2" targetFramework="net452" />
</packages>

View File

@@ -2,7 +2,7 @@
using System.Windows.Forms;
namespace TweetDck.Core.Controls{
public partial class FlatProgressBar : ProgressBar{
sealed partial class FlatProgressBar : ProgressBar{
private readonly SolidBrush brush;
public FlatProgressBar(){

View File

@@ -24,7 +24,6 @@
/// </summary>
private void InitializeComponent() {
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormBrowser));
this.trayIcon = new TweetDck.Core.TrayIcon();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.SuspendLayout();
@@ -38,7 +37,7 @@
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(324, 386);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Icon = Properties.Resources.icon;
this.Location = new System.Drawing.Point(-32000, -32000);
this.MinimumSize = new System.Drawing.Size(340, 424);
this.Name = "FormBrowser";

View File

@@ -73,7 +73,7 @@ namespace TweetDck.Core{
private void ShowChildForm(Form form){
form.Show(this);
form.MoveToCenter(this);
form.Shown += (sender, args) => form.MoveToCenter(this);
}
private void ForceClose(){
@@ -101,6 +101,12 @@ namespace TweetDck.Core{
private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){
if (!e.IsLoading){
browser.AddWordToDictionary("tweetdeck");
browser.AddWordToDictionary("TweetDeck");
browser.AddWordToDictionary("tweetduck");
browser.AddWordToDictionary("TweetDuck");
browser.AddWordToDictionary("TD");
Invoke(new Action(SetupWindow));
browser.LoadingStateChanged -= Browser_LoadingStateChanged;
}
@@ -112,6 +118,7 @@ namespace TweetDck.Core{
if (plugins.HasAnyPlugin(PluginEnvironment.Browser)){
ScriptLoader.ExecuteFile(e.Frame, PluginManager.PluginBrowserScriptFile);
ScriptLoader.ExecuteFile(e.Frame, PluginManager.PluginGlobalScriptFile);
plugins.ExecutePlugins(e.Frame, PluginEnvironment.Browser, true);
}
}
@@ -230,7 +237,7 @@ namespace TweetDck.Core{
else{
bool prevEnableUpdateCheck = Config.EnableUpdateCheck;
currentFormSettings = new FormSettings(this,updates);
currentFormSettings = new FormSettings(this, plugins, updates);
currentFormSettings.FormClosed += (sender, args) => {
currentFormSettings = null;

View File

@@ -117,267 +117,11 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="trayIcon.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>112, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAMAMDAAAAEAIACoJQAANgAAACAgAAABACAAqBAAAN4lAAAQEAAAAQAgAGgEAACGNgAAKAAAADAA
AABgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHg5IrF+OlS+hjyMw4g7tcmM
PM/MjTzezY485s2OPObMjjzfyIw80MOJPLe8hDyNs387WKx8OyQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApHU4FrB8OGXGijzAzo889dKR
PP/SkTz/0pE8/9GRPP/RkDz/0JA8/9CQPP/RkDz/0ZE8/9KRPP/TkTz/0pE8/86PPPbGijzCt4E8bKp6
OxoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKN1OB+9hTuLzI486NOR
PP/SkTz/0ZA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQ
PP/SkTz/0pE8/82OPOu9hTuOq3w8IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACidTkFuoM8csyN
POrTkjz/0ZE8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GRPP/Tkjz/zY887bqEPHimeDsHAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKp6
OynDiDvA05I8/9GRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0ZA8/9ORPP/GijzFr308LgAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAArXw7UM2OPOvTkTz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/SkTz/zo887rOAPFYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACxfjxm0ZA8/NGRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0ZE8/9GQPP64gjxtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAALaBPGXRkTz/0ZE8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQPP/SkTz/uIM8bAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqnk6TtCQPPzRkTz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkDz/0ZA8/rSA
PFUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACtfDwmzo887dKRPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0ZE8/86PPPGtfDwrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZ4PAXFijzC0pE8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CURf/TpGT/2baJ/9/GpP/l0bf/59W//+fVvf/kz7P/3sOg/9mz
hP/ToWH/0JND/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KRPP/EiTvJo3Y7CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALiC
PG/Tkjz/0JA8/9CQPP/QkDz/0JA8/9CSQf/Vq3P/5tO7//j07v//////////////////////////////
////////////////////////9vHq/+TQtf/UqG7/0JA+/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Tkjz/uYM8dgAAAAAAAAAAAAAAAAAA
AAAAAAAArXw8Gc2OPOzRkTz/0JA8/9CQPP/QlEX/27qP//fz7P//////////////////////////////
////////////////////////////////////////////////////////8ObZ/9auev/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/zI488J1x
OB8AAAAAAAAAAAAAAAAAAAAAuoM7h9OSPP/QkDz/0JA8/9GXTf/TpGb/27uS/9u6kP/ewZz/59W9//Xv
5///////////////////////////////////////////////////////////////////////////////
///r3cr/0ZxV/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/1JI8/7mDO5AAAAAAAAAAAAAAAADFj0cR0pNB6s+PO//Ojjv/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CRQP/TpGf/5NC2//38+v//////////////////////////////////////////////
////////////////////////+vf0/9auev/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0ZE8/8uOPO6SajYVAAAAAAAAAADzr1df7qxV/+WkT//ZmUT/0JA9/86O
O//Pjzv/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GaUv/l07r/////////////////////////
///////////////////////////////////////////////////buo//0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9OSPP+ldjdoAAAAAAAAAADurFW67qxV//Ct
Vv/vrVb/6adR/92dSP/Skz//zo47/8+PO//QkDz/0JA8/9CQPP/QkDz/0JJB/9Smaf/dv5j/+fXw////
////////////////////////////////////////////////////////////////////////2riM/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KRPP/FiTzGoHQ6Ae6s
VRrurFXz7qxV/+6sVf/urFX/761W//CuVv/sqlT/4qFM/9aVQv/Pjzv/zo47/9CQPP/VqnH/8+vh////
////////////////////////////////////////////////////////////////////////////////
/////////////9aueP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQ
PP/Ojzz4oHM5Iu6sVU3urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/vrVX/8K5W/+6sVf/mpU//2plF/9q6
j///////////////////////////////////////////////////////////////////////////////
//////////////////////////////n18P/Rm1P/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/SkTz/rXs6Vu6sVYPurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/wrVb/6r2B////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////o18L/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/v4Y8j+6sVa3urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFb/9Onb///////+/v3/////////////////////////////////////////
////////////////////////////////////////////////////////////////////////1qx2/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/wYc7uO6sVcrurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/trlr/67Zy/+m+h//y5NP/////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////7+TW/9CQPf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/yYw80e6s
VdvurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/6sme//v49P//////////////
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////9arc//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/RkDz/zI083+6sVeLurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/u2b3/////////
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////+fVvv/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/zo885u6sVeLurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+vL
of//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////r28v/Rl0r/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/zo885u6sVdrurFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7LBj//r28f//////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///Vq3P/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkDz/zI083+6sVcrurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/6cKO////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////ewp7/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/yYw80O6s
VazurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7NOy//z59v/u2b7/+fPr////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////n1sD/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/SkTz/xIo8uO6sVYHurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/67Zx/+2uWf/qy6H/////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////v5dj/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/SkTz/vYU8je6sVUvurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nC
kP///////////////////////////////////////////////////////fz6//fu5P/w4Mv/793F//7+
/v/////////////////////////////////////////////////////////////////17eT/0JA//86O
Ov/Pjzv/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/tYA8Vu6sVRnurFXy7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7a5b//fw5///////////////////////////////////////+/jz/+7av//pwIr/67Jn/+6t
Vv/urFX/6rd1////////////////////////////////////////////////////////////////////
///48ej/6KhU/92cR//Tkj7/zo47/8+PO//QkDz/0JA8/9GQPP/Pjzz3rXw8IAAAAADurFW37qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/6b2D//////////////////////////////////nz6//qyZ3/7K9h/+6s
Vf/urFX/7qxV/+6sVf/urFX/6rl6////////////////////////////////////////////////////
///////////////////9/Pr/6r6C//CuV//sqlT/4aBL/9aWQv/Pjzv/zo47/9GRPP/GijzCp3g8AQAA
AADurFVb7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/68yk///////////////////////+/fz/68+q/+2v
XP/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/6rNr//7+/f//////////////////////////////
/////////////////////////////////////////////+nEk//vrVX/8K5W/+6sVf/lpE//2ZlF/9KR
Pf+zfzpoAAAAAAAAAADurFUP7qxV5u6sVf/urFX/7qxV/+6sVf/urFX/7NGu//////////////////fu
5P/quHb/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxW//Xr3///////////////
///////////////////////////////////////////////////7+PP/+vXu///////pxJL/7qxV/+6s
Vf/wrVb/8K1W/+mnUevUmUsUAAAAAAAAAAAAAAAA7qxVgO6sVf/urFX/7qxV/+6sVf/urFX/6sqg////
////////8eLO/+yvX//urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nF
lf/////////////////////////////////////////////////////////////////8+vf/6cWV/+q5
ev/s07H/6rd1/+6sVf/urFX/7qxV/++tVogAAAAAAAAAAAAAAAAAAAAA7qxVFe6sVejurFX/7qxV/+6s
Vf/urFX/6bp8///////w4Mn/7a1Z/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/x4cz////////////////////////////////////////////////////+//7+
/v/////////+/+m8gP/urFX/7a1Y/+6sVf/urFX/7qxV7O6sVRoAAAAAAAAAAAAAAAAAAAAAAAAAAO6s
VWburFX/7qxV/+6sVf/urFX/7a5b/+zTs//sr1//7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/sr1//8uPQ////////////////////////////////////
////////6suj/+qzav/pxpj/9Onb//n07f/rr2D/7qxV/+6sVf/urFX/7qxVbwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAO6sVQPurFW67qxV/+6sVf/urFX/7qxV/+6sVv/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7axY/+nGl//27uP/////////
/////////fz6//Lj0P/qunv/7qxV/+6sVf/urFX/7qxV/+m9gv/qt3X/7qxV/+6sVf/urFXB7qxVBQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADurFUg7qxV6O6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/qtnP/6sqg/+3WuP/s07P/6cSS/+uyZf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVv/trVr/7qxV/+6s
VezurFUlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVRu6sVfjurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV++6sVUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6s
VVzurFX97qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxVYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADurFVd7qxV+O6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVfvurFVjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVR+6sVeXurFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV6O6sVU0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVSPurFW37qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFW77qxVJgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADurFUB7qxVae6sVeTurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV5+6sVW3urFUDAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVRjurFWA7qxV4u6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVeTurFWE7qxVGwAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVEu6sVV7urFW17qxV7+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVfDurFW47qxVX+6s
VRMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7qxVG+6sVUzurFWA7qxVrO6sVcnurFXa7qxV4u6sVeLurFXa7qxVye6sVa3urFWC7qxVTe6s
VR0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP//gAH//6gr//wAAD//qCv/8AAAD/+oK//AAAAD/6gr/4AAAAH/qCv/AAAAAP+oK/4A
AAAAf6gr/AAAAAA/qCv4AAAAAB+oK/AAAAAAD6gr4AAAAAAHqCvgAAAAAAeoK8AAAAAAA6grwAAAAAAD
qCuAAAAAAAGoK4AAAAAAAagrgAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAAqCsAAAAAAACoKwAA
AAAAAKgrAAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAA
qCsAAAAAAACoKwAAAAAAAKgrgAAAAAAAqCuAAAAAAAGoK4AAAAAAAagrwAAAAAADqCvAAAAAAAOoK+AA
AAAAB6gr4AAAAAAHqCvwAAAAAA+oK/gAAAAAH6gr/AAAAAA/qCv+AAAAAH+oK/8AAAAA/6gr/4AAAAH/
qCv/wAAAA/+oK//wAAAP/6gr//wAAD//qCv//4AB//+oKygAAAAgAAAAQAAAAAEAIAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApHY4FrR/
Ole+hjuVxos7w8uNPNvOjzznzo8858uNPNzGijzEvoU7l7WBO1mpejsYAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHg5Kr6F
O5XLjTvo0pE8/9ORPP/SkTz/0ZE8/9CQPP/QkDz/0ZE8/9KRPP/TkTz/0pE8/82OPOq/hjyZrXw7LAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3U6CbuE
O4bPjzz005I8/9GRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0ZE8/9OS
PP/PkDz1vYU8iah6PAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKR3
OibGizvG05E8/9GQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9GQPP/TkTz/yIs8yqx8PCkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AACsezsxy40849KRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/zI485rKAPTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAApXc6JMuNPOTSkTz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/zI485659PCcAAAAAAAAAAAAA
AAAAAAAAAAAAAKd4OwnHizzJ0pE8/9CQPP/QkDz/0JA9/9OgYP/YtIX/38Sh/+LMr//iy67/3sOf/9iy
gv/Tn13/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/x4s8zaV4
OwsAAAAAAAAAAAAAAAAAAAAAu4Q8hNOSPP/QkDz/0JA8/9GXS//YtIX/6NfC//Xv5//8+vj/////////
///8+vf/9O3k/+fVvv/YsYH/0JRF/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/Tkjz/u4Q7iQAAAAAAAAAAAAAAAKx7OyTPjzz10ZA8/9GXS//Ztoj/8une////////////////////
///////////////////////////////////38uz/3L2V/9CRP//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9GRPP/Ojzz3onU5KQAAAAAAAAAAxo1BlNGQO//Ojjv/0JNC/9GWSP/QlET/0ZpR/9au
eP/n1b3//v79////////////////////////////////////////////7+TV/9GdWP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9SSPP+4gjqaAAAAAPGuVhHvrVXq5qRO/9qZRP/QkT3/zo46/8+P
O//QkDz/0JA8/9CQPP/To2P/8+vh////////////////////////////////////////////+fXw/9Oh
Yf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0pE8/8qMO+2WbTYV7qxVUe6sVf/wrVb/761W/+mo
Uv/enUj/05M//86PO//PkD7/3cCZ//Lp3v/7+PT/////////////////////////////////////////
////////+PTv/9GcVf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/05I8/699OljurFWR7qxV/+6s
Vf/urFX/761W//CuV//sqlT/4qJQ/+zdyf//////////////////////////////////////////////
////////////////////////7+TV/9CRP//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Tkjz/vIQ7mO6s
Vb/urFX/7qxV/+6sVf/urFX/7qxV/++tVf/ry5///v79//7+/f//////////////////////////////
////////////////////////////////////////2rqO/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KR
PP/GijvF7qxV2u6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+u1bv/t1bb//fv4////////////////////
///////////////////////////////////////////////////48+3/0ZRG/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0ZA8/8uNPNzurFXl7qxV/+6sVf/urFX/7qxV/+6sVf/rsWP/9OjZ////////////////////
///////////////////////////////////////////////////////////////////YtIX/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/zo886O6sVeXurFX/7qxV/+6sVf/urFX/7qxW//Hiz///////////////
/////////////////////////////////////////////////////////////////////////////+rb
yP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Ojzzo7qxV2e6sVf/urFX/7qxV/+6sVf/quHb/////////
////////////////////////////////////////////////////////////////////////////////
////////+fXw/9CURf/QkDz/0JA8/9CQPP/QkDz/0ZA8/8yOPNzurFW/7qxV/+6sVf/urFX/7qxV/+nA
if/s1LT/9Onb////////////////////////////////////////////////////////////////////
////////////////////////0Z5b/9CQPP/QkDz/0JA8/9CQPP/SkTz/x4s8xe6sVY/urFX/7qxV/+6s
Vf/urFX/7qxV/+nEk//+/fz////////////////////////////+/v3/+PHo//To2f/+/v7/////////
///////////////////////////////////VqGz/zo46/8+PO//QkDz/0JA8/9KRPP+/hjyX7qxVUO6s
Vf/urFX/7qxV/+6sVf/ssGH//Pr2///////////////////////y49D/6cOR/+qyaf/urVb/6rJp////
/////////////////////////////////////////////+e7f//goEr/1ZVB/8+PO//Ojzv/0pE8/7WB
PFfurFUQ7qxV6O6sVf/urFX/7qxV/+m+hv/////////////////z5tX/6rl6/+6sVf/urFX/7qxV/+6s
Vf/qs2r////+////////////////////////////////////////////+PLp/+y4c//urFX/5aRO/9qZ
RP/Mjjztp3g6FQAAAADurFWQ7qxV/+6sVf/urFX/6cKP////////////682m/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+2sV//17N////////////////////////////////////////7+/v/06Nn/8uTT/+qz
a//wrVb/761W/+alUZYAAAAAAAAAAO6sVSHurFX07qxV/+6sVf/quXj//////+nDkf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+m+hP////////////////////////////////////////////jy
6v/qtnH/67Fj/+6sVf/urFX2761WJQAAAAAAAAAAAAAAAO6sVX7urFX/7qxV/+2vW//pvID/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nEkv/7+PT//////////////////fz6/+rJ
n//rtW7/682n/+zTs//urFb/7qxV/+6sVYQAAAAAAAAAAAAAAAAAAAAA7qxVB+6sVcTurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+u0bP/qy6H/7da4/+vN
pv/qtnP/7qxV/+6sVf/urFX/7K9f/+2sWP/urFXI7qxVCQAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVIO6s
VeDurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV4+6sVSMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7qxVLO6sVd/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVeLurFUwAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA7qxVIu6sVcHurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXE7qxVJAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVBu6sVX/urFXw7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXy7qxVgu6sVQgAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVSXurFWP7qxV5e6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXl7qxVke6sVScAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADurFUS7qxVUO6sVY7urFW97qxV2O6sVeXurFXl7qxV2O6sVb7urFWP7qxVUu6sVRMAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AD//8AAP/8AAA/+AAAH/AAAA/gAAAHwAAAA8AA
AAOAAAABgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA
AAGAAAABwAAAA8AAAAPgAAAH8AAAD/gAAB/8AAA//wAA///AA/8oAAAAEAAAACAAAAABACAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKx7Oja9hTqTyYw8zs6PPOfOjzznyYw8zr6G
PJSvfjw3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3Y7CbyEO5PRkDz805I8/9GRPP/QkDz/0JA8/9GR
PP/TkTz/0ZA8/b+GPJWrfDwKAAAAAAAAAAAAAAAAp3g8CcSJPLfTkjz/0ZA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/Tkjz/xoo8uqx8PQoAAAAAAAAAAL2FPJPUk0D/06Rm/92/mf/izK//4sut/9u6
j//Snlr/0JA8/9CQPP/QkDz/0JA8/9OSPP+9hTyWAAAAALiEQDLQkDz90JpS/93Amf/u4tP/////////
/////////fv5/+DIqP/QkkH/0JA8/9CQPP/RkDz/0JA8/qN1OTTtq1WS56VP/9qaRf/RkT3/0JdO/+rc
yP//////////////////////693L/9CSQf/QkDz/0JA8/9SSPP+3gTqW761Vz++tVv/wrVb/6K5h//fy
6v/////////////////////////////////gx6b/0JA8/9CQPP/RkTz/yYw80e6sVefurFX/7qxV/+q+
hP/69vD//////////////////////////////////fz7/9GbU//QkDz/0JA8/8+PPOnurFXn7qxV/+yw
Y//79/P////////////////////////////////////////////ZuIz/0JA8/9CQPP/Pjzzp7qxVz+6s
Vf/sr2H/8eLO/////////////v7+//n07f/+/v7/////////////////48yu/8+PO//Qjzv/yYs80e6s
VZLurFX/67Jm//7+/f/8+fb/68yl/+qza//rsmf//v37//////////////////Pn2P/ip1n/2phC/8CH
PJXurFUw7qxV/eq2c//169//6rNr/+6sVf/urFX/7q1W//Pm1f/////////////////8+fX/67+G/++t
Vf3lpVEyAAAAAO6sVZHtrVr/7a9c/+6sVf/urFX/7qxV/+6sVf/rsWP/7de5//Lj0P/pxJL/67Zy/+qz
av/urFWTAAAAAAAAAADurFUI7qxVtO6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFW37qxVCQAAAAAAAAAAAAAAAO6sVQjurFWQ7qxV++6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
VfvurFWS7qxVCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVTPurFWQ7qxVzO6sVeburFXm7qxVzO6s
VZDurFU0AAAAAAAAAAAAAAAAAAAAAPAPrEHAA6xBgAGsQYABrEEAAKxBAACsQQAArEEAAKxBAACsQQAA
rEEAAKxBAACsQYABrEGAAaxBwAOsQfAPrEE=
</value>
<data name="trayIcon.TrayLocation" type="System.Drawing.Point, System.Drawing">
<value>17, 17</value>
</data>
<data name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing">
<value>112, 17</value>
</data>
</root>

View File

@@ -112,7 +112,6 @@ namespace TweetDck.Core{
}
mouseHookDelegate = MouseHookProc;
mouseHook = NativeMethods.SetWindowsHookEx(NativeMethods.WH_MOUSE_LL,mouseHookDelegate,IntPtr.Zero,0);
Disposed += FormNotification_Disposed;
}
@@ -125,11 +124,26 @@ namespace TweetDck.Core{
base.WndProc(ref m);
}
// mouse wheel hook
private void StartMouseHook(){
if (mouseHook == IntPtr.Zero){
mouseHook = NativeMethods.SetWindowsHookEx(NativeMethods.WH_MOUSE_LL, mouseHookDelegate, IntPtr.Zero, 0);
}
}
private void StopMouseHook(){
if (mouseHook != IntPtr.Zero){
NativeMethods.UnhookWindowsHookEx(mouseHook);
mouseHook = IntPtr.Zero;
}
}
private IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam){
if (!ContainsFocus && wParam.ToInt32() == NativeMethods.WH_MOUSEWHEEL && browser.Bounds.Contains(PointToClient(Cursor.Position))){
// fuck it, Activate() doesn't work with this
Point prevPos = Cursor.Position;
Cursor.Position = PointToScreen(new Point(-1,-1));
Cursor.Position = PointToScreen(new Point(0, -1));
NativeMethods.SimulateMouseClick(NativeMethods.MouseButton.Left);
Cursor.Position = prevPos;
}
@@ -182,6 +196,7 @@ namespace TweetDck.Core{
if (plugins.HasAnyPlugin(PluginEnvironment.Notification)){
ScriptLoader.ExecuteScript(e.Frame, pluginJS, PluginScriptIdentifier);
ScriptLoader.ExecuteFile(e.Frame, PluginManager.PluginGlobalScriptFile);
plugins.ExecutePlugins(e.Frame, PluginEnvironment.Notification, false);
}
}
@@ -197,11 +212,7 @@ namespace TweetDck.Core{
private void FormNotification_Disposed(object sender, EventArgs e){
browser.Dispose();
if (mouseHook != IntPtr.Zero){
NativeMethods.UnhookWindowsHookEx(mouseHook);
mouseHook = IntPtr.Zero;
}
StopMouseHook();
}
// notification methods
@@ -237,6 +248,8 @@ namespace TweetDck.Core{
Location = new Point(-32000, -32000);
progressBarTimer.Value = Program.UserConfig.NotificationTimerCountDown ? 1000 : 0;
timerProgress.Stop();
StopMouseHook();
}
public void OnNotificationReady(){
@@ -332,6 +345,8 @@ namespace TweetDck.Core{
if (needsReactivating){
NativeMethods.SetFormPos(this, NativeMethods.HWND_TOPMOST, NativeMethods.SWP_NOACTIVATE);
}
StartMouseHook();
}
private void UpdateTitle(){

View File

@@ -0,0 +1,16 @@
using CefSharp;
using System;
namespace TweetDck.Core.Handling{
class BrowserProcessHandler : IBrowserProcessHandler{
void IBrowserProcessHandler.OnContextInitialized(){
using(IRequestContext ctx = Cef.GetGlobalRequestContext()){
string err;
ctx.SetPreference("browser.enable_spellchecking", Program.UserConfig.EnableSpellCheck, out err);
}
}
void IBrowserProcessHandler.OnScheduleMessagePumpWork(long delay){}
void IDisposable.Dispose(){}
}
}

View File

@@ -6,38 +6,38 @@ using TweetDck.Core.Utils;
namespace TweetDck.Core.Handling{
abstract class ContextMenuBase : IContextMenuHandler{
private const int MenuOpenUrlInBrowser = 26500;
private const int MenuCopyUrl = 26501;
private const int MenuOpenImageInBrowser = 26502;
private const int MenuOpenLinkUrl = 26500;
private const int MenuCopyLinkUrl = 26501;
private const int MenuOpenImage = 26502;
private const int MenuSaveImage = 26503;
private const int MenuCopyImageUrl = 26504;
public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && !parameters.UnfilteredLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal)){
model.AddItem((CefMenuCommand)MenuOpenUrlInBrowser,"Open in browser");
model.AddItem((CefMenuCommand)MenuCopyUrl,"Copy link address");
model.AddItem((CefMenuCommand)MenuOpenLinkUrl, "Open link in browser");
model.AddItem((CefMenuCommand)MenuCopyLinkUrl, "Copy link address");
model.AddSeparator();
}
if (parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents){
model.AddItem((CefMenuCommand)MenuOpenImageInBrowser,"Open image in browser");
model.AddItem((CefMenuCommand)MenuOpenImage, "Open image in browser");
model.AddItem((CefMenuCommand)MenuSaveImage, "Save image as...");
model.AddItem((CefMenuCommand)MenuCopyImageUrl,"Copy image URL");
model.AddItem((CefMenuCommand)MenuCopyImageUrl, "Copy image address");
model.AddSeparator();
}
}
public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
switch((int)commandId){
case MenuOpenUrlInBrowser:
case MenuOpenLinkUrl:
BrowserUtils.OpenExternalBrowser(parameters.LinkUrl);
break;
case MenuCopyUrl:
case MenuCopyLinkUrl:
Clipboard.SetText(string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedLink) ? parameters.UnfilteredLinkUrl : TweetDeckBridge.LastRightClickedLink, TextDataFormat.UnicodeText);
break;
case MenuOpenImageInBrowser:
case MenuOpenImage:
BrowserUtils.OpenExternalBrowser(parameters.SourceUrl);
break;
@@ -84,6 +84,12 @@ namespace TweetDck.Core.Handling{
}
}
protected static void AddSeparator(IMenuModel model){
if (model.Count > 0 && model.GetTypeAt(model.Count-1) != MenuItemType.Separator){ // do not add separators if there is nothing to separate
model.AddSeparator();
}
}
private static string GetImageFileName(string url){
// twimg adds a colon after file extension
int dot = url.LastIndexOf('.');

View File

@@ -1,15 +1,20 @@
using CefSharp;
using System.Windows.Forms;
using TweetDck.Core.Controls;
using TweetDck.Core.Utils;
namespace TweetDck.Core.Handling{
class ContextMenuBrowser : ContextMenuBase{
private const int MenuSettings = 26600;
private const int MenuPlugins = 26005;
private const int MenuAbout = 26601;
private const int MenuMute = 26602;
private const int MenuCopyTweetUrl = 26603;
private const int MenuCopyTweetEmbeddedUrl = 26604;
private const int MenuGlobal = 26600;
private const int MenuMute = 26601;
private const int MenuSettings = 26602;
private const int MenuPlugins = 26003;
private const int MenuAbout = 26604;
private const int MenuOpenTweetUrl = 26610;
private const int MenuCopyTweetUrl = 26611;
private const int MenuOpenQuotedTweetUrl = 26612;
private const int MenuCopyQuotedTweetUrl = 26613;
private readonly FormBrowser form;
@@ -24,31 +29,35 @@ namespace TweetDck.Core.Handling{
model.Remove(CefMenuCommand.ViewSource);
RemoveSeparatorIfLast(model);
if (!string.IsNullOrEmpty(TweetDeckBridge.LastHighlightedTweet)){
model.AddItem((CefMenuCommand)MenuCopyTweetUrl,"Copy tweet address");
if (!string.IsNullOrEmpty(TweetDeckBridge.LastHighlightedTweetEmbedded)){
model.AddItem((CefMenuCommand)MenuCopyTweetEmbeddedUrl,"Copy quoted tweet address");
}
model.AddSeparator();
}
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
if (model.Count > 0){
RemoveSeparatorIfLast(model);
if (!string.IsNullOrEmpty(TweetDeckBridge.LastHighlightedTweet) && (parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){
model.AddItem((CefMenuCommand)MenuOpenTweetUrl, "Open tweet in browser");
model.AddItem((CefMenuCommand)MenuCopyTweetUrl, "Copy tweet address");
if (!string.IsNullOrEmpty(TweetDeckBridge.LastHighlightedQuotedTweet)){
model.AddSeparator();
model.AddItem((CefMenuCommand)MenuOpenQuotedTweetUrl, "Open quoted tweet in browser");
model.AddItem((CefMenuCommand)MenuCopyQuotedTweetUrl, "Copy quoted tweet address");
}
model.AddSeparator();
}
model.AddItem(CefMenuCommand.Reload,"Reload");
model.AddCheckItem((CefMenuCommand)MenuMute,"Mute notifications");
model.SetChecked((CefMenuCommand)MenuMute,Program.UserConfig.MuteNotifications);
model.AddSeparator();
if ((parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){
AddSeparator(model);
model.AddItem((CefMenuCommand)MenuSettings,"Settings");
model.AddItem((CefMenuCommand)MenuPlugins,"Plugins");
model.AddItem((CefMenuCommand)MenuAbout,"About "+Program.BrandName);
IMenuModel globalMenu = model.Count == 0 ? model : model.AddSubMenu((CefMenuCommand)MenuGlobal, Program.BrandName);
globalMenu.AddItem(CefMenuCommand.Reload, "Reload browser");
globalMenu.AddCheckItem((CefMenuCommand)MenuMute, "Mute notifications");
globalMenu.SetChecked((CefMenuCommand)MenuMute, Program.UserConfig.MuteNotifications);
globalMenu.AddSeparator();
globalMenu.AddItem((CefMenuCommand)MenuSettings, "Settings");
globalMenu.AddItem((CefMenuCommand)MenuPlugins, "Plugins");
globalMenu.AddItem((CefMenuCommand)MenuAbout, "About "+Program.BrandName);
}
}
public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
@@ -81,12 +90,20 @@ namespace TweetDck.Core.Handling{
return true;
case MenuOpenTweetUrl:
BrowserUtils.OpenExternalBrowser(TweetDeckBridge.LastHighlightedTweet);
return true;
case MenuCopyTweetUrl:
Clipboard.SetText(TweetDeckBridge.LastHighlightedTweet, TextDataFormat.UnicodeText);
return true;
case MenuCopyTweetEmbeddedUrl:
Clipboard.SetText(TweetDeckBridge.LastHighlightedTweetEmbedded,TextDataFormat.UnicodeText);
case MenuOpenQuotedTweetUrl:
BrowserUtils.OpenExternalBrowser(TweetDeckBridge.LastHighlightedQuotedTweet);
return true;
case MenuCopyQuotedTweetUrl:
Clipboard.SetText(TweetDeckBridge.LastHighlightedQuotedTweet, TextDataFormat.UnicodeText);
return true;
}

View File

@@ -10,7 +10,7 @@ namespace TweetDck.Core.Handling{
class TweetDeckBridge{
public static string LastRightClickedLink = string.Empty;
public static string LastHighlightedTweet = string.Empty;
public static string LastHighlightedTweetEmbedded = string.Empty;
public static string LastHighlightedQuotedTweet = string.Empty;
public static string NotificationTweetEmbedded = string.Empty;
public static string ClipboardImagePath = string.Empty;
@@ -74,10 +74,10 @@ namespace TweetDck.Core.Handling{
form.InvokeSafe(() => LastRightClickedLink = link);
}
public void SetLastHighlightedTweet(string link, string embeddedLink){
public void SetLastHighlightedTweet(string link, string quotedLink){
form.InvokeSafe(() => {
LastHighlightedTweet = link;
LastHighlightedTweetEmbedded = embeddedLink;
LastHighlightedQuotedTweet = quotedLink;
});
}
@@ -133,7 +133,7 @@ namespace TweetDck.Core.Handling{
form.OnImagePasted();
}catch(Exception e){
Program.HandleException("Could not paste image from clipboard.",e);
Program.Reporter.HandleException("Clipboard Image Error", "Could not paste image from clipboard.", true, e);
}
}
});
@@ -155,6 +155,19 @@ namespace TweetDck.Core.Handling{
BrowserUtils.OpenExternalBrowser(url);
}
public void Alert(string type, string contents){
MessageBoxIcon icon;
switch(type){
case "error": icon = MessageBoxIcon.Error; break;
case "warning": icon = MessageBoxIcon.Warning; break;
case "info": icon = MessageBoxIcon.Information; break;
default: icon = MessageBoxIcon.None; break;
}
MessageBox.Show(contents, Program.BrandName+" Browser Message", MessageBoxButtons.OK, icon);
}
public void Log(string data){
System.Diagnostics.Debug.WriteLine(data);
}

View File

@@ -43,11 +43,16 @@ namespace TweetDck.Core.Handling{
build.Append(@"<header class='tweet-header'>");
build.Append(@"<time class='tweet-timestamp js-timestamp pull-right txt-mute'><a target='_blank' rel='url' href='https://twitter.com/chylexmc' class='txt-small'>0s</a></time>");
build.Append(@"<a target='_blank' rel='user' href='https://twitter.com/chylexmc' class='account-link link-complex block'>");
build.Append(@"<div class='obj-left item-img tweet-img'><img width='48' height='48' alt='chylexmc's avatar' src='https://pbs.twimg.com/profile_images/645532929930608642/J56NBJVY_normal.png' class='tweet-avatar avatar pull-right'></div>");
build.Append(@"<div class='obj-left item-img tweet-img'><img width='48' height='48' alt='chylexmc's avatar' src='https://pbs.twimg.com/profile_images/765161905312980992/AhDP9iY-_normal.jpg' class='tweet-avatar avatar pull-right'></div>");
build.Append(@"<div class='nbfc'><span class='account-inline txt-ellipsis'><b class='fullname link-complex-target'>chylex</b> <span class='username txt-mute'>@chylexmc</span></span></div>");
build.Append(@"</a>");
build.Append(@"</header>");
build.Append(@"<div class='tweet-body'><p class='js-tweet-text tweet-text with-linebreaks'>This is an example tweet, which lets you test the location and duration of popup notifications.</p></div>");
#if DEBUG
build.Append(@"<div style='margin-top:64px'>Scrollbar test padding...</div>");
#endif
build.Append(@"</div></div></article>");
return new TweetNotification(build.ToString(), "", 95);

79
Core/Other/FormMessage.Designer.cs generated Normal file
View File

@@ -0,0 +1,79 @@
namespace TweetDck.Core.Other {
partial class FormMessage {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.panelActions = new System.Windows.Forms.Panel();
this.labelMessage = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// panelActions
//
this.panelActions.BackColor = System.Drawing.SystemColors.Control;
this.panelActions.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panelActions.Location = new System.Drawing.Point(0, 84);
this.panelActions.Name = "panelActions";
this.panelActions.Size = new System.Drawing.Size(233, 49);
this.panelActions.TabIndex = 0;
//
// labelMessage
//
this.labelMessage.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.labelMessage.AutoSize = true;
this.labelMessage.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.labelMessage.Location = new System.Drawing.Point(62, 33);
this.labelMessage.Margin = new System.Windows.Forms.Padding(53, 24, 27, 24);
this.labelMessage.MaximumSize = new System.Drawing.Size(600, 0);
this.labelMessage.MinimumSize = new System.Drawing.Size(0, 24);
this.labelMessage.Name = "labelMessage";
this.labelMessage.Size = new System.Drawing.Size(0, 24);
this.labelMessage.TabIndex = 1;
this.labelMessage.SizeChanged += new System.EventHandler(this.labelMessage_SizeChanged);
//
// FormMessage
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(98, 133);
this.Controls.Add(this.labelMessage);
this.Controls.Add(this.panelActions);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FormMessage";
this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Panel panelActions;
private System.Windows.Forms.Label labelMessage;
}
}

114
Core/Other/FormMessage.cs Normal file
View File

@@ -0,0 +1,114 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TweetDck.Core.Other{
sealed partial class FormMessage : Form{
public Button ClickedButton { get; private set; }
private readonly Icon icon;
private readonly bool isReady;
private int realFormWidth, minFormWidth;
private int buttonCount;
private int prevLabelWidth, prevLabelHeight;
private bool wasLabelMultiline;
public FormMessage(string caption, string text, MessageBoxIcon messageIcon){
InitializeComponent();
this.prevLabelWidth = labelMessage.Width;
this.prevLabelHeight = labelMessage.Height;
this.minFormWidth = 18;
switch(messageIcon){
case MessageBoxIcon.Information:
icon = SystemIcons.Information;
break;
case MessageBoxIcon.Warning:
icon = SystemIcons.Warning;
break;
case MessageBoxIcon.Error:
icon = SystemIcons.Error;
break;
default:
icon = null;
labelMessage.Location = new Point(labelMessage.Location.X-32, labelMessage.Location.Y);
break;
}
this.isReady = true;
this.Text = caption;
this.labelMessage.Text = text;
}
public Button AddButton(string title){
Button button = new Button{
Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
Location = new Point(Width-112-buttonCount*96, 12),
Size = new Size(88, 26),
TabIndex = buttonCount,
Text = title,
UseVisualStyleBackColor = true
};
button.Click += (sender, args) => {
ClickedButton = (Button)sender;
DialogResult = DialogResult.OK;
Close();
};
panelActions.Controls.Add(button);
minFormWidth += 96;
Width = Math.Max(realFormWidth, minFormWidth);
++buttonCount;
return button;
}
public void AddActionControl(Control control){
panelActions.Controls.Add(control);
minFormWidth += control.Width+control.Margin.Horizontal;
Width = Math.Max(realFormWidth, minFormWidth);
}
private void labelMessage_SizeChanged(object sender, EventArgs e){
if (!isReady){
return;
}
bool isMultiline = labelMessage.Height > labelMessage.MinimumSize.Height;
if (isMultiline && !wasLabelMultiline){
labelMessage.Location = new Point(labelMessage.Location.X, labelMessage.Location.Y-8);
prevLabelHeight += 8;
}
else if (!isMultiline && wasLabelMultiline){
labelMessage.Location = new Point(labelMessage.Location.X, labelMessage.Location.Y+8);
prevLabelHeight -= 8;
}
realFormWidth = Width-(icon == null ? 32+35+(labelMessage.Margin.Left-labelMessage.Margin.Right) : 0)+labelMessage.Margin.Right+labelMessage.Width-prevLabelWidth;
Width = Math.Max(realFormWidth, minFormWidth);
Height += labelMessage.Height-prevLabelHeight;
prevLabelWidth = labelMessage.Width;
prevLabelHeight = labelMessage.Height;
wasLabelMultiline = isMultiline;
}
protected override void OnPaint(PaintEventArgs e){
if (icon != null){
e.Graphics.DrawIcon(icon, 25, 26);
}
base.OnPaint(e);
}
}
}

View File

@@ -23,7 +23,6 @@
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormPlugins));
this.btnClose = new System.Windows.Forms.Button();
this.btnReload = new System.Windows.Forms.Button();
this.btnOpenFolder = new System.Windows.Forms.Button();
@@ -69,7 +68,7 @@
this.btnOpenFolder.UseVisualStyleBackColor = true;
this.btnOpenFolder.Click += new System.EventHandler(this.btnOpenFolder_Click);
//
// pluginList
// tabPanelPlugins
//
this.tabPanelPlugins.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
@@ -88,11 +87,10 @@
this.Controls.Add(this.btnOpenFolder);
this.Controls.Add(this.btnReload);
this.Controls.Add(this.btnClose);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Icon = global::TweetDck.Properties.Resources.icon;
this.MinimumSize = new System.Drawing.Size(480, 320);
this.Name = "FormPlugins";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Plugins";
this.ResumeLayout(false);
this.PerformLayout();

View File

@@ -1,5 +1,7 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using TweetDck.Core.Controls;
using TweetDck.Plugins;
@@ -7,7 +9,7 @@ using TweetDck.Plugins.Controls;
using TweetDck.Plugins.Events;
namespace TweetDck.Core.Other{
partial class FormPlugins : Form{
sealed partial class FormPlugins : Form{
private readonly PluginManager pluginManager;
private readonly TabButton tabBtnOfficial, tabBtnCustom;
private readonly PluginListFlowLayout flowLayoutPlugins;
@@ -16,6 +18,8 @@ namespace TweetDck.Core.Other{
public FormPlugins(){
InitializeComponent();
Text = Program.BrandName+" Plugins";
}
public FormPlugins(PluginManager pluginManager) : this(){
@@ -58,8 +62,17 @@ namespace TweetDck.Core.Other{
flowLayoutPlugins.SuspendLayout();
flowLayoutPlugins.Controls.Clear();
foreach(Plugin plugin in pluginManager.GetPluginsByGroup(selectedGroup.Value)){
flowLayoutPlugins.Controls.Add(new PluginControl(pluginManager,plugin));
Plugin[] plugins = pluginManager.GetPluginsByGroup(selectedGroup.Value).OrderBy(plugin => !plugin.CanRun ? 0 : pluginManager.Config.IsEnabled(plugin) ? 1 : 2).ThenBy(plugin => plugin.Name).ToArray();
for(int index = 0; index < plugins.Length; index++){
flowLayoutPlugins.Controls.Add(new PluginControl(pluginManager, plugins[index]));
if (index < plugins.Length-1){
flowLayoutPlugins.Controls.Add(new Panel{
BackColor = Color.DimGray,
Size = new Size(1, 1)
});
}
}
flowLayoutPlugins_Resize(flowLayoutPlugins, new EventArgs());
@@ -72,11 +85,22 @@ namespace TweetDck.Core.Other{
}
private void flowLayoutPlugins_Resize(object sender, EventArgs e){
int horizontalOffset = 8+(flowLayoutPlugins.VerticalScroll.Visible ? SystemInformation.VerticalScrollBarWidth : 0);
if (flowLayoutPlugins.Controls.Count == 0){
return;
}
Control lastControl = flowLayoutPlugins.Controls[flowLayoutPlugins.Controls.Count-1];
bool showScrollBar = lastControl.Location.Y+lastControl.Height >= flowLayoutPlugins.Height;
int horizontalOffset = showScrollBar ? SystemInformation.VerticalScrollBarWidth : 0;
flowLayoutPlugins.AutoScroll = showScrollBar;
flowLayoutPlugins.VerticalScroll.Visible = showScrollBar;
foreach(Control control in flowLayoutPlugins.Controls){
control.Width = flowLayoutPlugins.Width-control.Margin.Horizontal-horizontalOffset;
}
flowLayoutPlugins.Focus();
}
private void btnOpenFolder_Click(object sender, EventArgs e){
@@ -84,9 +108,11 @@ namespace TweetDck.Core.Other{
}
private void btnReload_Click(object sender, EventArgs e){
if (MessageBox.Show("This will also reload the browser window. Do you want to proceed?", "Reloading Plugins", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes){
pluginManager.Reload();
ReloadPluginTab();
}
}
private void btnClose_Click(object sender, EventArgs e){
Close();

View File

@@ -117,261 +117,4 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAMAMDAAAAEAIACoJQAANgAAACAgAAABACAAqBAAAN4lAAAQEAAAAQAgAGgEAACGNgAAKAAAADAA
AABgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHg5IrF+OlS+hjyMw4g7tcmM
PM/MjTzezY485s2OPObMjjzfyIw80MOJPLe8hDyNs387WKx8OyQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApHU4FrB8OGXGijzAzo889dKR
PP/SkTz/0pE8/9GRPP/RkDz/0JA8/9CQPP/RkDz/0ZE8/9KRPP/TkTz/0pE8/86PPPbGijzCt4E8bKp6
OxoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKN1OB+9hTuLzI486NOR
PP/SkTz/0ZA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQ
PP/SkTz/0pE8/82OPOu9hTuOq3w8IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACidTkFuoM8csyN
POrTkjz/0ZE8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GRPP/Tkjz/zY887bqEPHimeDsHAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKp6
OynDiDvA05I8/9GRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0ZA8/9ORPP/GijzFr308LgAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAArXw7UM2OPOvTkTz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/SkTz/zo887rOAPFYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACxfjxm0ZA8/NGRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0ZE8/9GQPP64gjxtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAALaBPGXRkTz/0ZE8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQPP/SkTz/uIM8bAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqnk6TtCQPPzRkTz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkDz/0ZA8/rSA
PFUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACtfDwmzo887dKRPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0ZE8/86PPPGtfDwrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZ4PAXFijzC0pE8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CURf/TpGT/2baJ/9/GpP/l0bf/59W//+fVvf/kz7P/3sOg/9mz
hP/ToWH/0JND/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KRPP/EiTvJo3Y7CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALiC
PG/Tkjz/0JA8/9CQPP/QkDz/0JA8/9CSQf/Vq3P/5tO7//j07v//////////////////////////////
////////////////////////9vHq/+TQtf/UqG7/0JA+/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Tkjz/uYM8dgAAAAAAAAAAAAAAAAAA
AAAAAAAArXw8Gc2OPOzRkTz/0JA8/9CQPP/QlEX/27qP//fz7P//////////////////////////////
////////////////////////////////////////////////////////8ObZ/9auev/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/zI488J1x
OB8AAAAAAAAAAAAAAAAAAAAAuoM7h9OSPP/QkDz/0JA8/9GXTf/TpGb/27uS/9u6kP/ewZz/59W9//Xv
5///////////////////////////////////////////////////////////////////////////////
///r3cr/0ZxV/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/1JI8/7mDO5AAAAAAAAAAAAAAAADFj0cR0pNB6s+PO//Ojjv/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CRQP/TpGf/5NC2//38+v//////////////////////////////////////////////
////////////////////////+vf0/9auev/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0ZE8/8uOPO6SajYVAAAAAAAAAADzr1df7qxV/+WkT//ZmUT/0JA9/86O
O//Pjzv/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GaUv/l07r/////////////////////////
///////////////////////////////////////////////////buo//0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9OSPP+ldjdoAAAAAAAAAADurFW67qxV//Ct
Vv/vrVb/6adR/92dSP/Skz//zo47/8+PO//QkDz/0JA8/9CQPP/QkDz/0JJB/9Smaf/dv5j/+fXw////
////////////////////////////////////////////////////////////////////////2riM/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KRPP/FiTzGoHQ6Ae6s
VRrurFXz7qxV/+6sVf/urFX/761W//CuVv/sqlT/4qFM/9aVQv/Pjzv/zo47/9CQPP/VqnH/8+vh////
////////////////////////////////////////////////////////////////////////////////
/////////////9aueP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQ
PP/Ojzz4oHM5Iu6sVU3urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/vrVX/8K5W/+6sVf/mpU//2plF/9q6
j///////////////////////////////////////////////////////////////////////////////
//////////////////////////////n18P/Rm1P/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/SkTz/rXs6Vu6sVYPurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/wrVb/6r2B////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////o18L/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/v4Y8j+6sVa3urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFb/9Onb///////+/v3/////////////////////////////////////////
////////////////////////////////////////////////////////////////////////1qx2/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/wYc7uO6sVcrurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/trlr/67Zy/+m+h//y5NP/////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////7+TW/9CQPf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/yYw80e6s
VdvurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/6sme//v49P//////////////
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////9arc//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/RkDz/zI083+6sVeLurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/u2b3/////////
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////+fVvv/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/zo885u6sVeLurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+vL
of//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////r28v/Rl0r/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/zo885u6sVdrurFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7LBj//r28f//////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///Vq3P/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkDz/zI083+6sVcrurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/6cKO////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////ewp7/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/yYw80O6s
VazurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7NOy//z59v/u2b7/+fPr////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////n1sD/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/SkTz/xIo8uO6sVYHurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/67Zx/+2uWf/qy6H/////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////v5dj/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/SkTz/vYU8je6sVUvurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nC
kP///////////////////////////////////////////////////////fz6//fu5P/w4Mv/793F//7+
/v/////////////////////////////////////////////////////////////////17eT/0JA//86O
Ov/Pjzv/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/tYA8Vu6sVRnurFXy7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7a5b//fw5///////////////////////////////////////+/jz/+7av//pwIr/67Jn/+6t
Vv/urFX/6rd1////////////////////////////////////////////////////////////////////
///48ej/6KhU/92cR//Tkj7/zo47/8+PO//QkDz/0JA8/9GQPP/Pjzz3rXw8IAAAAADurFW37qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/6b2D//////////////////////////////////nz6//qyZ3/7K9h/+6s
Vf/urFX/7qxV/+6sVf/urFX/6rl6////////////////////////////////////////////////////
///////////////////9/Pr/6r6C//CuV//sqlT/4aBL/9aWQv/Pjzv/zo47/9GRPP/GijzCp3g8AQAA
AADurFVb7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/68yk///////////////////////+/fz/68+q/+2v
XP/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/6rNr//7+/f//////////////////////////////
/////////////////////////////////////////////+nEk//vrVX/8K5W/+6sVf/lpE//2ZlF/9KR
Pf+zfzpoAAAAAAAAAADurFUP7qxV5u6sVf/urFX/7qxV/+6sVf/urFX/7NGu//////////////////fu
5P/quHb/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxW//Xr3///////////////
///////////////////////////////////////////////////7+PP/+vXu///////pxJL/7qxV/+6s
Vf/wrVb/8K1W/+mnUevUmUsUAAAAAAAAAAAAAAAA7qxVgO6sVf/urFX/7qxV/+6sVf/urFX/6sqg////
////////8eLO/+yvX//urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nF
lf/////////////////////////////////////////////////////////////////8+vf/6cWV/+q5
ev/s07H/6rd1/+6sVf/urFX/7qxV/++tVogAAAAAAAAAAAAAAAAAAAAA7qxVFe6sVejurFX/7qxV/+6s
Vf/urFX/6bp8///////w4Mn/7a1Z/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/x4cz////////////////////////////////////////////////////+//7+
/v/////////+/+m8gP/urFX/7a1Y/+6sVf/urFX/7qxV7O6sVRoAAAAAAAAAAAAAAAAAAAAAAAAAAO6s
VWburFX/7qxV/+6sVf/urFX/7a5b/+zTs//sr1//7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/sr1//8uPQ////////////////////////////////////
////////6suj/+qzav/pxpj/9Onb//n07f/rr2D/7qxV/+6sVf/urFX/7qxVbwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAO6sVQPurFW67qxV/+6sVf/urFX/7qxV/+6sVv/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7axY/+nGl//27uP/////////
/////////fz6//Lj0P/qunv/7qxV/+6sVf/urFX/7qxV/+m9gv/qt3X/7qxV/+6sVf/urFXB7qxVBQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADurFUg7qxV6O6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/qtnP/6sqg/+3WuP/s07P/6cSS/+uyZf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVv/trVr/7qxV/+6s
VezurFUlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVRu6sVfjurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV++6sVUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6s
VVzurFX97qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxVYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADurFVd7qxV+O6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVfvurFVjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVR+6sVeXurFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV6O6sVU0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVSPurFW37qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFW77qxVJgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADurFUB7qxVae6sVeTurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV5+6sVW3urFUDAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVRjurFWA7qxV4u6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVeTurFWE7qxVGwAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVEu6sVV7urFW17qxV7+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVfDurFW47qxVX+6s
VRMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7qxVG+6sVUzurFWA7qxVrO6sVcnurFXa7qxV4u6sVeLurFXa7qxVye6sVa3urFWC7qxVTe6s
VR0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP//gAH//6gr//wAAD//qCv/8AAAD/+oK//AAAAD/6gr/4AAAAH/qCv/AAAAAP+oK/4A
AAAAf6gr/AAAAAA/qCv4AAAAAB+oK/AAAAAAD6gr4AAAAAAHqCvgAAAAAAeoK8AAAAAAA6grwAAAAAAD
qCuAAAAAAAGoK4AAAAAAAagrgAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAAqCsAAAAAAACoKwAA
AAAAAKgrAAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAA
qCsAAAAAAACoKwAAAAAAAKgrgAAAAAAAqCuAAAAAAAGoK4AAAAAAAagrwAAAAAADqCvAAAAAAAOoK+AA
AAAAB6gr4AAAAAAHqCvwAAAAAA+oK/gAAAAAH6gr/AAAAAA/qCv+AAAAAH+oK/8AAAAA/6gr/4AAAAH/
qCv/wAAAA/+oK//wAAAP/6gr//wAAD//qCv//4AB//+oKygAAAAgAAAAQAAAAAEAIAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApHY4FrR/
Ole+hjuVxos7w8uNPNvOjzznzo8858uNPNzGijzEvoU7l7WBO1mpejsYAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHg5Kr6F
O5XLjTvo0pE8/9ORPP/SkTz/0ZE8/9CQPP/QkDz/0ZE8/9KRPP/TkTz/0pE8/82OPOq/hjyZrXw7LAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3U6CbuE
O4bPjzz005I8/9GRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0ZE8/9OS
PP/PkDz1vYU8iah6PAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKR3
OibGizvG05E8/9GQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9GQPP/TkTz/yIs8yqx8PCkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AACsezsxy40849KRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/zI485rKAPTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAApXc6JMuNPOTSkTz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/zI485659PCcAAAAAAAAAAAAA
AAAAAAAAAAAAAKd4OwnHizzJ0pE8/9CQPP/QkDz/0JA9/9OgYP/YtIX/38Sh/+LMr//iy67/3sOf/9iy
gv/Tn13/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/x4s8zaV4
OwsAAAAAAAAAAAAAAAAAAAAAu4Q8hNOSPP/QkDz/0JA8/9GXS//YtIX/6NfC//Xv5//8+vj/////////
///8+vf/9O3k/+fVvv/YsYH/0JRF/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/Tkjz/u4Q7iQAAAAAAAAAAAAAAAKx7OyTPjzz10ZA8/9GXS//Ztoj/8une////////////////////
///////////////////////////////////38uz/3L2V/9CRP//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9GRPP/Ojzz3onU5KQAAAAAAAAAAxo1BlNGQO//Ojjv/0JNC/9GWSP/QlET/0ZpR/9au
eP/n1b3//v79////////////////////////////////////////////7+TV/9GdWP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9SSPP+4gjqaAAAAAPGuVhHvrVXq5qRO/9qZRP/QkT3/zo46/8+P
O//QkDz/0JA8/9CQPP/To2P/8+vh////////////////////////////////////////////+fXw/9Oh
Yf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0pE8/8qMO+2WbTYV7qxVUe6sVf/wrVb/761W/+mo
Uv/enUj/05M//86PO//PkD7/3cCZ//Lp3v/7+PT/////////////////////////////////////////
////////+PTv/9GcVf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/05I8/699OljurFWR7qxV/+6s
Vf/urFX/761W//CuV//sqlT/4qJQ/+zdyf//////////////////////////////////////////////
////////////////////////7+TV/9CRP//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Tkjz/vIQ7mO6s
Vb/urFX/7qxV/+6sVf/urFX/7qxV/++tVf/ry5///v79//7+/f//////////////////////////////
////////////////////////////////////////2rqO/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KR
PP/GijvF7qxV2u6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+u1bv/t1bb//fv4////////////////////
///////////////////////////////////////////////////48+3/0ZRG/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0ZA8/8uNPNzurFXl7qxV/+6sVf/urFX/7qxV/+6sVf/rsWP/9OjZ////////////////////
///////////////////////////////////////////////////////////////////YtIX/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/zo886O6sVeXurFX/7qxV/+6sVf/urFX/7qxW//Hiz///////////////
/////////////////////////////////////////////////////////////////////////////+rb
yP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Ojzzo7qxV2e6sVf/urFX/7qxV/+6sVf/quHb/////////
////////////////////////////////////////////////////////////////////////////////
////////+fXw/9CURf/QkDz/0JA8/9CQPP/QkDz/0ZA8/8yOPNzurFW/7qxV/+6sVf/urFX/7qxV/+nA
if/s1LT/9Onb////////////////////////////////////////////////////////////////////
////////////////////////0Z5b/9CQPP/QkDz/0JA8/9CQPP/SkTz/x4s8xe6sVY/urFX/7qxV/+6s
Vf/urFX/7qxV/+nEk//+/fz////////////////////////////+/v3/+PHo//To2f/+/v7/////////
///////////////////////////////////VqGz/zo46/8+PO//QkDz/0JA8/9KRPP+/hjyX7qxVUO6s
Vf/urFX/7qxV/+6sVf/ssGH//Pr2///////////////////////y49D/6cOR/+qyaf/urVb/6rJp////
/////////////////////////////////////////////+e7f//goEr/1ZVB/8+PO//Ojzv/0pE8/7WB
PFfurFUQ7qxV6O6sVf/urFX/7qxV/+m+hv/////////////////z5tX/6rl6/+6sVf/urFX/7qxV/+6s
Vf/qs2r////+////////////////////////////////////////////+PLp/+y4c//urFX/5aRO/9qZ
RP/Mjjztp3g6FQAAAADurFWQ7qxV/+6sVf/urFX/6cKP////////////682m/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+2sV//17N////////////////////////////////////////7+/v/06Nn/8uTT/+qz
a//wrVb/761W/+alUZYAAAAAAAAAAO6sVSHurFX07qxV/+6sVf/quXj//////+nDkf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+m+hP////////////////////////////////////////////jy
6v/qtnH/67Fj/+6sVf/urFX2761WJQAAAAAAAAAAAAAAAO6sVX7urFX/7qxV/+2vW//pvID/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nEkv/7+PT//////////////////fz6/+rJ
n//rtW7/682n/+zTs//urFb/7qxV/+6sVYQAAAAAAAAAAAAAAAAAAAAA7qxVB+6sVcTurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+u0bP/qy6H/7da4/+vN
pv/qtnP/7qxV/+6sVf/urFX/7K9f/+2sWP/urFXI7qxVCQAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVIO6s
VeDurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV4+6sVSMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7qxVLO6sVd/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVeLurFUwAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA7qxVIu6sVcHurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXE7qxVJAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVBu6sVX/urFXw7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXy7qxVgu6sVQgAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVSXurFWP7qxV5e6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXl7qxVke6sVScAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADurFUS7qxVUO6sVY7urFW97qxV2O6sVeXurFXl7qxV2O6sVb7urFWP7qxVUu6sVRMAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AD//8AAP/8AAA/+AAAH/AAAA/gAAAHwAAAA8AA
AAOAAAABgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA
AAGAAAABwAAAA8AAAAPgAAAH8AAAD/gAAB/8AAA//wAA///AA/8oAAAAEAAAACAAAAABACAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKx7Oja9hTqTyYw8zs6PPOfOjzznyYw8zr6G
PJSvfjw3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3Y7CbyEO5PRkDz805I8/9GRPP/QkDz/0JA8/9GR
PP/TkTz/0ZA8/b+GPJWrfDwKAAAAAAAAAAAAAAAAp3g8CcSJPLfTkjz/0ZA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/Tkjz/xoo8uqx8PQoAAAAAAAAAAL2FPJPUk0D/06Rm/92/mf/izK//4sut/9u6
j//Snlr/0JA8/9CQPP/QkDz/0JA8/9OSPP+9hTyWAAAAALiEQDLQkDz90JpS/93Amf/u4tP/////////
/////////fv5/+DIqP/QkkH/0JA8/9CQPP/RkDz/0JA8/qN1OTTtq1WS56VP/9qaRf/RkT3/0JdO/+rc
yP//////////////////////693L/9CSQf/QkDz/0JA8/9SSPP+3gTqW761Vz++tVv/wrVb/6K5h//fy
6v/////////////////////////////////gx6b/0JA8/9CQPP/RkTz/yYw80e6sVefurFX/7qxV/+q+
hP/69vD//////////////////////////////////fz7/9GbU//QkDz/0JA8/8+PPOnurFXn7qxV/+yw
Y//79/P////////////////////////////////////////////ZuIz/0JA8/9CQPP/Pjzzp7qxVz+6s
Vf/sr2H/8eLO/////////////v7+//n07f/+/v7/////////////////48yu/8+PO//Qjzv/yYs80e6s
VZLurFX/67Jm//7+/f/8+fb/68yl/+qza//rsmf//v37//////////////////Pn2P/ip1n/2phC/8CH
PJXurFUw7qxV/eq2c//169//6rNr/+6sVf/urFX/7q1W//Pm1f/////////////////8+fX/67+G/++t
Vf3lpVEyAAAAAO6sVZHtrVr/7a9c/+6sVf/urFX/7qxV/+6sVf/rsWP/7de5//Lj0P/pxJL/67Zy/+qz
av/urFWTAAAAAAAAAADurFUI7qxVtO6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFW37qxVCQAAAAAAAAAAAAAAAO6sVQjurFWQ7qxV++6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
VfvurFWS7qxVCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVTPurFWQ7qxVzO6sVeburFXm7qxVzO6s
VZDurFU0AAAAAAAAAAAAAAAAAAAAAPAPrEHAA6xBgAGsQYABrEEAAKxBAACsQQAArEEAAKxBAACsQQAA
rEEAAKxBAACsQYABrEGAAaxBwAOsQfAPrEE=
</value>
</data>
</root>

View File

@@ -23,7 +23,6 @@
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormSettings));
this.btnClose = new System.Windows.Forms.Button();
this.labelTip = new System.Windows.Forms.Label();
this.tabPanel = new TweetDck.Core.Controls.TabPanel();
@@ -70,7 +69,7 @@
this.Controls.Add(this.btnClose);
this.Controls.Add(this.tabPanel);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Icon = Properties.Resources.icon;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FormSettings";

View File

@@ -3,14 +3,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using TweetDck.Core.Other.Settings;
using TweetDck.Core.Other.Settings.Export;
using TweetDck.Plugins;
using TweetDck.Updates;
namespace TweetDck.Core.Other{
sealed partial class FormSettings : Form{
private readonly Dictionary<Type, BaseTabSettings> tabs = new Dictionary<Type, BaseTabSettings>(4);
public FormSettings(FormBrowser browserForm, UpdateHandler updates){
public FormSettings(FormBrowser browserForm, PluginManager plugins, UpdateHandler updates){
InitializeComponent();
Text = Program.BrandName+" Settings";
@@ -19,7 +19,7 @@ namespace TweetDck.Core.Other{
this.tabPanel.AddButton("General", SelectTab<TabSettingsGeneral>);
this.tabPanel.AddButton("Notifications", () => SelectTab(() => new TabSettingsNotifications(browserForm.CreateNotificationForm(false))));
this.tabPanel.AddButton("Updates", () => SelectTab(() => new TabSettingsUpdates(updates)));
this.tabPanel.AddButton("Advanced",() => SelectTab(() => new TabSettingsAdvanced(browserForm.ReloadBrowser)));
this.tabPanel.AddButton("Advanced", () => SelectTab(() => new TabSettingsAdvanced(browserForm.ReloadBrowser, plugins)));
this.tabPanel.SelectTab(tabPanel.Buttons.First());
}

View File

@@ -117,261 +117,4 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAMAMDAAAAEAIACoJQAANgAAACAgAAABACAAqBAAAN4lAAAQEAAAAQAgAGgEAACGNgAAKAAAADAA
AABgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHg5IrF+OlS+hjyMw4g7tcmM
PM/MjTzezY485s2OPObMjjzfyIw80MOJPLe8hDyNs387WKx8OyQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApHU4FrB8OGXGijzAzo889dKR
PP/SkTz/0pE8/9GRPP/RkDz/0JA8/9CQPP/RkDz/0ZE8/9KRPP/TkTz/0pE8/86PPPbGijzCt4E8bKp6
OxoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKN1OB+9hTuLzI486NOR
PP/SkTz/0ZA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQ
PP/SkTz/0pE8/82OPOu9hTuOq3w8IgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACidTkFuoM8csyN
POrTkjz/0ZE8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GRPP/Tkjz/zY887bqEPHimeDsHAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKp6
OynDiDvA05I8/9GRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0ZA8/9ORPP/GijzFr308LgAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAArXw7UM2OPOvTkTz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/SkTz/zo887rOAPFYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACxfjxm0ZA8/NGRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0ZE8/9GQPP64gjxtAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAALaBPGXRkTz/0ZE8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQPP/SkTz/uIM8bAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqnk6TtCQPPzRkTz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkDz/0ZA8/rSA
PFUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACtfDwmzo887dKRPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0ZE8/86PPPGtfDwrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKZ4PAXFijzC0pE8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CURf/TpGT/2baJ/9/GpP/l0bf/59W//+fVvf/kz7P/3sOg/9mz
hP/ToWH/0JND/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KRPP/EiTvJo3Y7CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALiC
PG/Tkjz/0JA8/9CQPP/QkDz/0JA8/9CSQf/Vq3P/5tO7//j07v//////////////////////////////
////////////////////////9vHq/+TQtf/UqG7/0JA+/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Tkjz/uYM8dgAAAAAAAAAAAAAAAAAA
AAAAAAAArXw8Gc2OPOzRkTz/0JA8/9CQPP/QlEX/27qP//fz7P//////////////////////////////
////////////////////////////////////////////////////////8ObZ/9auev/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/zI488J1x
OB8AAAAAAAAAAAAAAAAAAAAAuoM7h9OSPP/QkDz/0JA8/9GXTf/TpGb/27uS/9u6kP/ewZz/59W9//Xv
5///////////////////////////////////////////////////////////////////////////////
///r3cr/0ZxV/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/1JI8/7mDO5AAAAAAAAAAAAAAAADFj0cR0pNB6s+PO//Ojjv/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CRQP/TpGf/5NC2//38+v//////////////////////////////////////////////
////////////////////////+vf0/9auev/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0ZE8/8uOPO6SajYVAAAAAAAAAADzr1df7qxV/+WkT//ZmUT/0JA9/86O
O//Pjzv/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GaUv/l07r/////////////////////////
///////////////////////////////////////////////////buo//0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9OSPP+ldjdoAAAAAAAAAADurFW67qxV//Ct
Vv/vrVb/6adR/92dSP/Skz//zo47/8+PO//QkDz/0JA8/9CQPP/QkDz/0JJB/9Smaf/dv5j/+fXw////
////////////////////////////////////////////////////////////////////////2riM/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KRPP/FiTzGoHQ6Ae6s
VRrurFXz7qxV/+6sVf/urFX/761W//CuVv/sqlT/4qFM/9aVQv/Pjzv/zo47/9CQPP/VqnH/8+vh////
////////////////////////////////////////////////////////////////////////////////
/////////////9aueP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9GQ
PP/Ojzz4oHM5Iu6sVU3urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/vrVX/8K5W/+6sVf/mpU//2plF/9q6
j///////////////////////////////////////////////////////////////////////////////
//////////////////////////////n18P/Rm1P/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/SkTz/rXs6Vu6sVYPurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/wrVb/6r2B////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////o18L/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/v4Y8j+6sVa3urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFb/9Onb///////+/v3/////////////////////////////////////////
////////////////////////////////////////////////////////////////////////1qx2/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/wYc7uO6sVcrurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/trlr/67Zy/+m+h//y5NP/////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////7+TW/9CQPf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/yYw80e6s
VdvurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/6sme//v49P//////////////
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////9arc//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/RkDz/zI083+6sVeLurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/u2b3/////////
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////+fVvv/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/zo885u6sVeLurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+vL
of//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////r28v/Rl0r/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/zo885u6sVdrurFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7LBj//r28f//////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///Vq3P/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkDz/zI083+6sVcrurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/6cKO////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////ewp7/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/RkTz/yYw80O6s
VazurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7NOy//z59v/u2b7/+fPr////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////n1sD/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/SkTz/xIo8uO6sVYHurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/67Zx/+2uWf/qy6H/////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////v5dj/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/SkTz/vYU8je6sVUvurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nC
kP///////////////////////////////////////////////////////fz6//fu5P/w4Mv/793F//7+
/v/////////////////////////////////////////////////////////////////17eT/0JA//86O
Ov/Pjzv/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/tYA8Vu6sVRnurFXy7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7a5b//fw5///////////////////////////////////////+/jz/+7av//pwIr/67Jn/+6t
Vv/urFX/6rd1////////////////////////////////////////////////////////////////////
///48ej/6KhU/92cR//Tkj7/zo47/8+PO//QkDz/0JA8/9GQPP/Pjzz3rXw8IAAAAADurFW37qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/6b2D//////////////////////////////////nz6//qyZ3/7K9h/+6s
Vf/urFX/7qxV/+6sVf/urFX/6rl6////////////////////////////////////////////////////
///////////////////9/Pr/6r6C//CuV//sqlT/4aBL/9aWQv/Pjzv/zo47/9GRPP/GijzCp3g8AQAA
AADurFVb7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/68yk///////////////////////+/fz/68+q/+2v
XP/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/6rNr//7+/f//////////////////////////////
/////////////////////////////////////////////+nEk//vrVX/8K5W/+6sVf/lpE//2ZlF/9KR
Pf+zfzpoAAAAAAAAAADurFUP7qxV5u6sVf/urFX/7qxV/+6sVf/urFX/7NGu//////////////////fu
5P/quHb/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxW//Xr3///////////////
///////////////////////////////////////////////////7+PP/+vXu///////pxJL/7qxV/+6s
Vf/wrVb/8K1W/+mnUevUmUsUAAAAAAAAAAAAAAAA7qxVgO6sVf/urFX/7qxV/+6sVf/urFX/6sqg////
////////8eLO/+yvX//urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nF
lf/////////////////////////////////////////////////////////////////8+vf/6cWV/+q5
ev/s07H/6rd1/+6sVf/urFX/7qxV/++tVogAAAAAAAAAAAAAAAAAAAAA7qxVFe6sVejurFX/7qxV/+6s
Vf/urFX/6bp8///////w4Mn/7a1Z/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/x4cz////////////////////////////////////////////////////+//7+
/v/////////+/+m8gP/urFX/7a1Y/+6sVf/urFX/7qxV7O6sVRoAAAAAAAAAAAAAAAAAAAAAAAAAAO6s
VWburFX/7qxV/+6sVf/urFX/7a5b/+zTs//sr1//7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/sr1//8uPQ////////////////////////////////////
////////6suj/+qzav/pxpj/9Onb//n07f/rr2D/7qxV/+6sVf/urFX/7qxVbwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAO6sVQPurFW67qxV/+6sVf/urFX/7qxV/+6sVv/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7axY/+nGl//27uP/////////
/////////fz6//Lj0P/qunv/7qxV/+6sVf/urFX/7qxV/+m9gv/qt3X/7qxV/+6sVf/urFXB7qxVBQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADurFUg7qxV6O6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/qtnP/6sqg/+3WuP/s07P/6cSS/+uyZf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVv/trVr/7qxV/+6s
VezurFUlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVRu6sVfjurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV++6sVUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6s
VVzurFX97qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxVYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADurFVd7qxV+O6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVfvurFVjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVR+6sVeXurFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV6O6sVU0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVSPurFW37qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFW77qxVJgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADurFUB7qxVae6sVeTurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV5+6sVW3urFUDAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVRjurFWA7qxV4u6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVeTurFWE7qxVGwAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVEu6sVV7urFW17qxV7+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVfDurFW47qxVX+6s
VRMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7qxVG+6sVUzurFWA7qxVrO6sVcnurFXa7qxV4u6sVeLurFXa7qxVye6sVa3urFWC7qxVTe6s
VR0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP//gAH//6gr//wAAD//qCv/8AAAD/+oK//AAAAD/6gr/4AAAAH/qCv/AAAAAP+oK/4A
AAAAf6gr/AAAAAA/qCv4AAAAAB+oK/AAAAAAD6gr4AAAAAAHqCvgAAAAAAeoK8AAAAAAA6grwAAAAAAD
qCuAAAAAAAGoK4AAAAAAAagrgAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAAqCsAAAAAAACoKwAA
AAAAAKgrAAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAAqCsAAAAAAACoKwAAAAAAAKgrAAAAAAAA
qCsAAAAAAACoKwAAAAAAAKgrgAAAAAAAqCuAAAAAAAGoK4AAAAAAAagrwAAAAAADqCvAAAAAAAOoK+AA
AAAAB6gr4AAAAAAHqCvwAAAAAA+oK/gAAAAAH6gr/AAAAAA/qCv+AAAAAH+oK/8AAAAA/6gr/4AAAAH/
qCv/wAAAA/+oK//wAAAP/6gr//wAAD//qCv//4AB//+oKygAAAAgAAAAQAAAAAEAIAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApHY4FrR/
Ole+hjuVxos7w8uNPNvOjzznzo8858uNPNzGijzEvoU7l7WBO1mpejsYAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHg5Kr6F
O5XLjTvo0pE8/9ORPP/SkTz/0ZE8/9CQPP/QkDz/0ZE8/9KRPP/TkTz/0pE8/82OPOq/hjyZrXw7LAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3U6CbuE
O4bPjzz005I8/9GRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0ZE8/9OS
PP/PkDz1vYU8iah6PAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKR3
OibGizvG05E8/9GQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9GQPP/TkTz/yIs8yqx8PCkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AACsezsxy40849KRPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/zI485rKAPTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAApXc6JMuNPOTSkTz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/zI485659PCcAAAAAAAAAAAAA
AAAAAAAAAAAAAKd4OwnHizzJ0pE8/9CQPP/QkDz/0JA9/9OgYP/YtIX/38Sh/+LMr//iy67/3sOf/9iy
gv/Tn13/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/SkTz/x4s8zaV4
OwsAAAAAAAAAAAAAAAAAAAAAu4Q8hNOSPP/QkDz/0JA8/9GXS//YtIX/6NfC//Xv5//8+vj/////////
///8+vf/9O3k/+fVvv/YsYH/0JRF/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/Tkjz/u4Q7iQAAAAAAAAAAAAAAAKx7OyTPjzz10ZA8/9GXS//Ztoj/8une////////////////////
///////////////////////////////////38uz/3L2V/9CRP//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9GRPP/Ojzz3onU5KQAAAAAAAAAAxo1BlNGQO//Ojjv/0JNC/9GWSP/QlET/0ZpR/9au
eP/n1b3//v79////////////////////////////////////////////7+TV/9GdWP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/0JA8/9SSPP+4gjqaAAAAAPGuVhHvrVXq5qRO/9qZRP/QkT3/zo46/8+P
O//QkDz/0JA8/9CQPP/To2P/8+vh////////////////////////////////////////////+fXw/9Oh
Yf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/0pE8/8qMO+2WbTYV7qxVUe6sVf/wrVb/761W/+mo
Uv/enUj/05M//86PO//PkD7/3cCZ//Lp3v/7+PT/////////////////////////////////////////
////////+PTv/9GcVf/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/QkDz/05I8/699OljurFWR7qxV/+6s
Vf/urFX/761W//CuV//sqlT/4qJQ/+zdyf//////////////////////////////////////////////
////////////////////////7+TV/9CRP//QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Tkjz/vIQ7mO6s
Vb/urFX/7qxV/+6sVf/urFX/7qxV/++tVf/ry5///v79//7+/f//////////////////////////////
////////////////////////////////////////2rqO/9CQPP/QkDz/0JA8/9CQPP/QkDz/0JA8/9KR
PP/GijvF7qxV2u6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+u1bv/t1bb//fv4////////////////////
///////////////////////////////////////////////////48+3/0ZRG/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0ZA8/8uNPNzurFXl7qxV/+6sVf/urFX/7qxV/+6sVf/rsWP/9OjZ////////////////////
///////////////////////////////////////////////////////////////////YtIX/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/QkDz/zo886O6sVeXurFX/7qxV/+6sVf/urFX/7qxW//Hiz///////////////
/////////////////////////////////////////////////////////////////////////////+rb
yP/QkDz/0JA8/9CQPP/QkDz/0JA8/9CQPP/Ojzzo7qxV2e6sVf/urFX/7qxV/+6sVf/quHb/////////
////////////////////////////////////////////////////////////////////////////////
////////+fXw/9CURf/QkDz/0JA8/9CQPP/QkDz/0ZA8/8yOPNzurFW/7qxV/+6sVf/urFX/7qxV/+nA
if/s1LT/9Onb////////////////////////////////////////////////////////////////////
////////////////////////0Z5b/9CQPP/QkDz/0JA8/9CQPP/SkTz/x4s8xe6sVY/urFX/7qxV/+6s
Vf/urFX/7qxV/+nEk//+/fz////////////////////////////+/v3/+PHo//To2f/+/v7/////////
///////////////////////////////////VqGz/zo46/8+PO//QkDz/0JA8/9KRPP+/hjyX7qxVUO6s
Vf/urFX/7qxV/+6sVf/ssGH//Pr2///////////////////////y49D/6cOR/+qyaf/urVb/6rJp////
/////////////////////////////////////////////+e7f//goEr/1ZVB/8+PO//Ojzv/0pE8/7WB
PFfurFUQ7qxV6O6sVf/urFX/7qxV/+m+hv/////////////////z5tX/6rl6/+6sVf/urFX/7qxV/+6s
Vf/qs2r////+////////////////////////////////////////////+PLp/+y4c//urFX/5aRO/9qZ
RP/Mjjztp3g6FQAAAADurFWQ7qxV/+6sVf/urFX/6cKP////////////682m/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+2sV//17N////////////////////////////////////////7+/v/06Nn/8uTT/+qz
a//wrVb/761W/+alUZYAAAAAAAAAAO6sVSHurFX07qxV/+6sVf/quXj//////+nDkf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+m+hP////////////////////////////////////////////jy
6v/qtnH/67Fj/+6sVf/urFX2761WJQAAAAAAAAAAAAAAAO6sVX7urFX/7qxV/+2vW//pvID/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+nEkv/7+PT//////////////////fz6/+rJ
n//rtW7/682n/+zTs//urFb/7qxV/+6sVYQAAAAAAAAAAAAAAAAAAAAA7qxVB+6sVcTurFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+u0bP/qy6H/7da4/+vN
pv/qtnP/7qxV/+6sVf/urFX/7K9f/+2sWP/urFXI7qxVCQAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVIO6s
VeDurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV4+6sVSMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7qxVLO6sVd/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVeLurFUwAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA7qxVIu6sVcHurFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXE7qxVJAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7qxVBu6sVX/urFXw7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXy7qxVgu6sVQgAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVSXurFWP7qxV5e6s
Vf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFXl7qxVke6sVScAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADurFUS7qxVUO6sVY7urFW97qxV2O6sVeXurFXl7qxV2O6sVb7urFWP7qxVUu6sVRMAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AD//8AAP/8AAA/+AAAH/AAAA/gAAAHwAAAA8AA
AAOAAAABgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA
AAGAAAABwAAAA8AAAAPgAAAH8AAAD/gAAB/8AAA//wAA///AA/8oAAAAEAAAACAAAAABACAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKx7Oja9hTqTyYw8zs6PPOfOjzznyYw8zr6G
PJSvfjw3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo3Y7CbyEO5PRkDz805I8/9GRPP/QkDz/0JA8/9GR
PP/TkTz/0ZA8/b+GPJWrfDwKAAAAAAAAAAAAAAAAp3g8CcSJPLfTkjz/0ZA8/9CQPP/QkDz/0JA8/9CQ
PP/QkDz/0JA8/9CQPP/Tkjz/xoo8uqx8PQoAAAAAAAAAAL2FPJPUk0D/06Rm/92/mf/izK//4sut/9u6
j//Snlr/0JA8/9CQPP/QkDz/0JA8/9OSPP+9hTyWAAAAALiEQDLQkDz90JpS/93Amf/u4tP/////////
/////////fv5/+DIqP/QkkH/0JA8/9CQPP/RkDz/0JA8/qN1OTTtq1WS56VP/9qaRf/RkT3/0JdO/+rc
yP//////////////////////693L/9CSQf/QkDz/0JA8/9SSPP+3gTqW761Vz++tVv/wrVb/6K5h//fy
6v/////////////////////////////////gx6b/0JA8/9CQPP/RkTz/yYw80e6sVefurFX/7qxV/+q+
hP/69vD//////////////////////////////////fz7/9GbU//QkDz/0JA8/8+PPOnurFXn7qxV/+yw
Y//79/P////////////////////////////////////////////ZuIz/0JA8/9CQPP/Pjzzp7qxVz+6s
Vf/sr2H/8eLO/////////////v7+//n07f/+/v7/////////////////48yu/8+PO//Qjzv/yYs80e6s
VZLurFX/67Jm//7+/f/8+fb/68yl/+qza//rsmf//v37//////////////////Pn2P/ip1n/2phC/8CH
PJXurFUw7qxV/eq2c//169//6rNr/+6sVf/urFX/7q1W//Pm1f/////////////////8+fX/67+G/++t
Vf3lpVEyAAAAAO6sVZHtrVr/7a9c/+6sVf/urFX/7qxV/+6sVf/rsWP/7de5//Lj0P/pxJL/67Zy/+qz
av/urFWTAAAAAAAAAADurFUI7qxVtO6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
Vf/urFW37qxVCQAAAAAAAAAAAAAAAO6sVQjurFWQ7qxV++6sVf/urFX/7qxV/+6sVf/urFX/7qxV/+6s
VfvurFWS7qxVCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO6sVTPurFWQ7qxVzO6sVeburFXm7qxVzO6s
VZDurFU0AAAAAAAAAAAAAAAAAAAAAPAPrEHAA6xBgAGsQYABrEEAAKxBAACsQQAArEEAAKxBAACsQQAA
rEEAAKxBAACsQYABrEGAAaxBwAOsQfAPrEE=
</value>
</data>
</root>

View File

@@ -1,4 +1,5 @@
using System.Windows.Forms;
using System.Diagnostics;
using System.Windows.Forms;
using TweetDck.Configuration;
namespace TweetDck.Core.Other.Settings{
@@ -12,7 +13,14 @@ namespace TweetDck.Core.Other.Settings{
public bool Ready { get; set; }
public BaseTabSettings(){
Padding = new Padding(6,6,6,6);
Padding = new Padding(6);
}
protected static void PromptRestart(){
if (MessageBox.Show("The application must restart for the setting to take place. Do you want to restart now?", Program.BrandName+" Settings", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes){
Process.Start(Application.ExecutablePath, "-restart");
Application.Exit();
}
}
}
}

View File

@@ -47,6 +47,7 @@
this.textBoxBrowserCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
this.textBoxBrowserCSS.Multiline = true;
this.textBoxBrowserCSS.Name = "textBoxBrowserCSS";
this.textBoxBrowserCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBoxBrowserCSS.Size = new System.Drawing.Size(226, 193);
this.textBoxBrowserCSS.TabIndex = 0;
this.textBoxBrowserCSS.WordWrap = false;
@@ -129,7 +130,8 @@
this.textBoxNotificationCSS.Margin = new System.Windows.Forms.Padding(0, 3, 0, 0);
this.textBoxNotificationCSS.Multiline = true;
this.textBoxNotificationCSS.Name = "textBoxNotificationCSS";
this.textBoxNotificationCSS.Size = new System.Drawing.Size(227, 193);
this.textBoxNotificationCSS.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBoxNotificationCSS.Size = new System.Drawing.Size(226, 193);
this.textBoxNotificationCSS.TabIndex = 1;
this.textBoxNotificationCSS.WordWrap = false;
//

View File

@@ -4,6 +4,8 @@ using System.Text;
namespace TweetDck.Core.Other.Settings.Export{
class CombinedFileStream : IDisposable{
public const char KeySeparator = '/';
private readonly Stream stream;
public CombinedFileStream(Stream stream){
@@ -11,6 +13,12 @@ namespace TweetDck.Core.Other.Settings.Export{
}
public void WriteFile(string identifier, string path){
byte[] name = Encoding.UTF8.GetBytes(identifier);
if (name.Length > 255){
throw new ArgumentOutOfRangeException("Identifier cannot be 256 or more characters long: "+identifier);
}
byte[] contents;
using(FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
@@ -26,12 +34,9 @@ namespace TweetDck.Core.Other.Settings.Export{
}
}
byte[] name = Encoding.UTF8.GetBytes(identifier);
byte[] contentsLength = BitConverter.GetBytes(contents.Length);
stream.WriteByte((byte)name.Length);
stream.Write(name, 0, name.Length);
stream.Write(contentsLength,0,4);
stream.Write(BitConverter.GetBytes(contents.Length), 0, 4);
stream.Write(contents, 0, contents.Length);
}
@@ -65,6 +70,13 @@ namespace TweetDck.Core.Other.Settings.Export{
public class Entry{
public string Identifier { get; private set; }
public string KeyName{
get{
int index = Identifier.IndexOf(KeySeparator);
return index == -1 ? Identifier : Identifier.Substring(0, index);
}
}
private readonly byte[] contents;
public Entry(string identifier, byte[] contents){
@@ -75,6 +87,15 @@ namespace TweetDck.Core.Other.Settings.Export{
public void WriteToFile(string path){
File.WriteAllBytes(path, contents);
}
public void WriteToFile(string path, bool createDirectory){
if (createDirectory){
// ReSharper disable once AssignNullToNotNullAttribute
Directory.CreateDirectory(Path.GetDirectoryName(path));
}
File.WriteAllBytes(path, contents);
}
}
}
}

View File

@@ -1,19 +1,25 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using TweetDck.Plugins;
namespace TweetDck.Core.Other.Settings.Export{
sealed class ExportManager{
public static readonly string CookiesPath = Path.Combine(Program.StoragePath,"Cookies");
public static readonly string TempCookiesPath = Path.Combine(Program.StoragePath,"CookiesTmp");
private static readonly string CookiesPath = Path.Combine(Program.StoragePath, "Cookies");
private static readonly string TempCookiesPath = Path.Combine(Program.StoragePath, "CookiesTmp");
public bool IsRestarting { get; private set; }
public Exception LastException { get; private set; }
private readonly string file;
private readonly PluginManager plugins;
public ExportManager(string file){
public ExportManager(string file, PluginManager plugins){
this.file = file;
this.plugins = plugins;
}
public bool Export(bool includeSession){
@@ -21,6 +27,35 @@ namespace TweetDck.Core.Other.Settings.Export{
using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None))){
stream.WriteFile("config", Program.ConfigFilePath);
foreach(PathInfo path in EnumerateFilesRelative(plugins.PathOfficialPlugins)){
string[] split = path.Relative.Split(CombinedFileStream.KeySeparator);
if (split.Length < 3){
continue;
}
else if (split.Length == 3){
if (split[2].Equals(".meta", StringComparison.OrdinalIgnoreCase) ||
split[2].Equals("browser.js", StringComparison.OrdinalIgnoreCase) ||
split[2].Equals("notification.js", StringComparison.OrdinalIgnoreCase)){
continue;
}
}
try{
stream.WriteFile("plugin.off"+path.Relative, path.Full);
}catch(ArgumentOutOfRangeException e){
MessageBox.Show("Could not include a file in the export. "+e.Message, "Export Profile", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
foreach(PathInfo path in EnumerateFilesRelative(plugins.PathCustomPlugins)){
try{
stream.WriteFile("plugin.usr"+path.Relative, path.Full);
}catch(ArgumentOutOfRangeException e){
MessageBox.Show("Could not include a file in the export. "+e.Message, "Export Profile", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
if (includeSession){
stream.WriteFile("cookies", CookiesPath);
}
@@ -37,21 +72,39 @@ namespace TweetDck.Core.Other.Settings.Export{
public bool Import(){
try{
bool updatedPlugins = false;
using(CombinedFileStream stream = new CombinedFileStream(new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.None))){
CombinedFileStream.Entry entry;
while((entry = stream.ReadFile()) != null){
switch(entry.Identifier){
switch(entry.KeyName){
case "config":
entry.WriteToFile(Program.ConfigFilePath);
Program.ReloadConfig();
break;
case "plugin.off":
string root = Path.Combine(plugins.PathOfficialPlugins, entry.Identifier.Split(CombinedFileStream.KeySeparator)[1]);
if (Directory.Exists(root)){
entry.WriteToFile(Path.Combine(plugins.PathOfficialPlugins, entry.Identifier.Substring(entry.KeyName.Length+1)), true);
updatedPlugins = true;
}
break;
case "plugin.usr":
entry.WriteToFile(Path.Combine(plugins.PathCustomPlugins, entry.Identifier.Substring(entry.KeyName.Length+1)), true);
updatedPlugins = true;
break;
case "cookies":
if (MessageBox.Show("Do you want to import the login session? This will restart "+Program.BrandName+".", "Importing "+Program.BrandName+" Settings", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes){
entry.WriteToFile(Path.Combine(Program.StoragePath, TempCookiesPath));
// okay to and restart, 'cookies' is always the last entry
IsRestarting = true;
Process.Start(Application.ExecutablePath, "-restart -importcookies");
Application.Exit();
}
@@ -61,11 +114,41 @@ namespace TweetDck.Core.Other.Settings.Export{
}
}
if (updatedPlugins){
plugins.Reload();
}
return true;
}catch(Exception e){
LastException = e;
return false;
}
}
public static void ImportCookies(){
if (File.Exists(TempCookiesPath)){
try{
if (File.Exists(CookiesPath)){
File.Delete(CookiesPath);
}
File.Move(TempCookiesPath, CookiesPath);
}catch(Exception e){
Program.Reporter.HandleException("Profile Import Error", "Could not import the cookie file to restore login session.", true, e);
}
}
}
private static IEnumerable<PathInfo> EnumerateFilesRelative(string root){
return Directory.EnumerateFiles(root, "*.*", SearchOption.AllDirectories).Select(fullPath => new PathInfo{
Full = fullPath,
Relative = fullPath.Substring(root.Length).Replace(Path.DirectorySeparatorChar, CombinedFileStream.KeySeparator) // includes leading separator character
});
}
private class PathInfo{
public string Full { get; set; }
public string Relative { get; set; }
}
}
}

View File

@@ -28,12 +28,12 @@
this.checkHardwareAcceleration = new System.Windows.Forms.CheckBox();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.btnEditCefArgs = new System.Windows.Forms.Button();
this.btnEditCSS = new System.Windows.Forms.Button();
this.btnReset = new System.Windows.Forms.Button();
this.btnImport = new System.Windows.Forms.Button();
this.btnExport = new System.Windows.Forms.Button();
this.groupPerformance = new System.Windows.Forms.GroupBox();
this.groupConfiguration = new System.Windows.Forms.GroupBox();
this.btnEditCSS = new System.Windows.Forms.Button();
this.groupPerformance.SuspendLayout();
this.groupConfiguration.SuspendLayout();
this.SuspendLayout();
@@ -75,11 +75,22 @@
this.btnEditCefArgs.UseVisualStyleBackColor = true;
this.btnEditCefArgs.Click += new System.EventHandler(this.btnEditCefArgs_Click);
//
// btnEditCSS
//
this.btnEditCSS.Location = new System.Drawing.Point(6, 48);
this.btnEditCSS.Name = "btnEditCSS";
this.btnEditCSS.Size = new System.Drawing.Size(171, 23);
this.btnEditCSS.TabIndex = 16;
this.btnEditCSS.Text = "Edit CSS";
this.toolTip.SetToolTip(this.btnEditCSS, "Set custom CSS for browser and notification windows.");
this.btnEditCSS.UseVisualStyleBackColor = true;
this.btnEditCSS.Click += new System.EventHandler(this.btnEditCSS_Click);
//
// btnReset
//
this.btnReset.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnReset.AutoSize = true;
this.btnReset.Location = new System.Drawing.Point(209, 250);
this.btnReset.Location = new System.Drawing.Point(190, 250);
this.btnReset.Name = "btnReset";
this.btnReset.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnReset.Size = new System.Drawing.Size(102, 23);
@@ -92,12 +103,12 @@
//
this.btnImport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnImport.AutoSize = true;
this.btnImport.Location = new System.Drawing.Point(109, 250);
this.btnImport.Location = new System.Drawing.Point(100, 250);
this.btnImport.Name = "btnImport";
this.btnImport.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnImport.Size = new System.Drawing.Size(94, 23);
this.btnImport.Size = new System.Drawing.Size(84, 23);
this.btnImport.TabIndex = 16;
this.btnImport.Text = "Import Settings";
this.btnImport.Text = "Import Profile";
this.btnImport.UseVisualStyleBackColor = true;
this.btnImport.Click += new System.EventHandler(this.btnImport_Click);
//
@@ -105,12 +116,13 @@
//
this.btnExport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnExport.AutoSize = true;
this.btnExport.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnExport.Location = new System.Drawing.Point(9, 250);
this.btnExport.Name = "btnExport";
this.btnExport.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.btnExport.Size = new System.Drawing.Size(94, 23);
this.btnExport.Size = new System.Drawing.Size(85, 23);
this.btnExport.TabIndex = 15;
this.btnExport.Text = "Export Settings";
this.btnExport.Text = "Export Profile";
this.btnExport.UseVisualStyleBackColor = true;
this.btnExport.Click += new System.EventHandler(this.btnExport_Click);
//
@@ -136,17 +148,6 @@
this.groupConfiguration.TabStop = false;
this.groupConfiguration.Text = "Configuration";
//
// btnEditCSS
//
this.btnEditCSS.Location = new System.Drawing.Point(6, 48);
this.btnEditCSS.Name = "btnEditCSS";
this.btnEditCSS.Size = new System.Drawing.Size(171, 23);
this.btnEditCSS.TabIndex = 16;
this.btnEditCSS.Text = "Edit CSS";
this.toolTip.SetToolTip(this.btnEditCSS, "Set custom CSS for browser and notification windows.");
this.btnEditCSS.UseVisualStyleBackColor = true;
this.btnEditCSS.Click += new System.EventHandler(this.btnEditCSS_Click);
//
// TabSettingsAdvanced
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);

View File

@@ -1,19 +1,21 @@
using System;
using System.Diagnostics;
using System.Windows.Forms;
using TweetDck.Core.Controls;
using TweetDck.Core.Other.Settings.Dialogs;
using TweetDck.Core.Other.Settings.Export;
using TweetDck.Core.Utils;
using TweetDck.Plugins;
namespace TweetDck.Core.Other.Settings{
partial class TabSettingsAdvanced : BaseTabSettings{
private readonly Action browserReloadAction;
private readonly PluginManager plugins;
public TabSettingsAdvanced(Action browserReloadAction){
public TabSettingsAdvanced(Action browserReloadAction, PluginManager plugins){
InitializeComponent();
this.browserReloadAction = browserReloadAction;
this.plugins = plugins;
checkHardwareAcceleration.Checked = HardwareAcceleration.IsEnabled;
@@ -109,10 +111,10 @@ namespace TweetDck.Core.Other.Settings{
if (file != null){
Program.UserConfig.Save();
ExportManager manager = new ExportManager(file);
ExportManager manager = new ExportManager(file, plugins);
if (!manager.Export(saveCredentials)){
Program.HandleException("An exception happened while exporting "+Program.BrandName+" settings.",manager.LastException);
Program.Reporter.HandleException("Profile Export Error", "An exception happened while exporting "+Program.BrandName+" settings.", true, manager.LastException);
}
}
}
@@ -130,13 +132,15 @@ namespace TweetDck.Core.Other.Settings{
}
if (file != null){
ExportManager manager = new ExportManager(file);
ExportManager manager = new ExportManager(file, plugins);
if (manager.Import()){
if (!manager.IsRestarting){
((FormSettings)ParentForm).ReloadUI();
}
}
else{
Program.HandleException("An exception happened while importing "+Program.BrandName+" settings.",manager.LastException);
Program.Reporter.HandleException("Profile Import Error", "An exception happened while importing "+Program.BrandName+" settings.", true, manager.LastException);
}
}
}
@@ -147,12 +151,5 @@ namespace TweetDck.Core.Other.Settings{
((FormSettings)ParentForm).ReloadUI();
}
}
private static void PromptRestart(){
if (MessageBox.Show("The application must restart for the setting to take place. Do you want to restart now?",Program.BrandName+" Settings",MessageBoxButtons.YesNo,MessageBoxIcon.Information) == DialogResult.Yes){
Process.Start(Application.ExecutablePath,"-restart");
Application.Exit();
}
}
}
}

View File

@@ -28,6 +28,7 @@
this.comboBoxTrayType = new System.Windows.Forms.ComboBox();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.checkTrayHighlight = new System.Windows.Forms.CheckBox();
this.checkSpellCheck = new System.Windows.Forms.CheckBox();
this.groupTray = new System.Windows.Forms.GroupBox();
this.labelTrayIcon = new System.Windows.Forms.Label();
this.groupInterface = new System.Windows.Forms.GroupBox();
@@ -74,12 +75,24 @@
this.checkTrayHighlight.UseVisualStyleBackColor = true;
this.checkTrayHighlight.CheckedChanged += new System.EventHandler(this.checkTrayHighlight_CheckedChanged);
//
// checkSpellCheck
//
this.checkSpellCheck.AutoSize = true;
this.checkSpellCheck.Location = new System.Drawing.Point(9, 44);
this.checkSpellCheck.Name = "checkSpellCheck";
this.checkSpellCheck.Size = new System.Drawing.Size(119, 17);
this.checkSpellCheck.TabIndex = 15;
this.checkSpellCheck.Text = "Enable Spell Check";
this.toolTip.SetToolTip(this.checkSpellCheck, "Underlines words that are spelled incorrectly.");
this.checkSpellCheck.UseVisualStyleBackColor = true;
this.checkSpellCheck.CheckedChanged += new System.EventHandler(this.checkSpellCheck_CheckedChanged);
//
// groupTray
//
this.groupTray.Controls.Add(this.checkTrayHighlight);
this.groupTray.Controls.Add(this.labelTrayIcon);
this.groupTray.Controls.Add(this.comboBoxTrayType);
this.groupTray.Location = new System.Drawing.Point(9, 63);
this.groupTray.Location = new System.Drawing.Point(9, 86);
this.groupTray.Name = "groupTray";
this.groupTray.Size = new System.Drawing.Size(183, 93);
this.groupTray.TabIndex = 15;
@@ -98,10 +111,11 @@
//
// groupInterface
//
this.groupInterface.Controls.Add(this.checkSpellCheck);
this.groupInterface.Controls.Add(this.checkExpandLinks);
this.groupInterface.Location = new System.Drawing.Point(9, 9);
this.groupInterface.Name = "groupInterface";
this.groupInterface.Size = new System.Drawing.Size(183, 48);
this.groupInterface.Size = new System.Drawing.Size(183, 71);
this.groupInterface.TabIndex = 16;
this.groupInterface.TabStop = false;
this.groupInterface.Text = "User Interface";
@@ -131,5 +145,6 @@
private System.Windows.Forms.GroupBox groupInterface;
private System.Windows.Forms.Label labelTrayIcon;
private System.Windows.Forms.CheckBox checkTrayHighlight;
private System.Windows.Forms.CheckBox checkSpellCheck;
}
}

View File

@@ -12,8 +12,9 @@ namespace TweetDck.Core.Other.Settings{
comboBoxTrayType.Items.Add("Combined");
comboBoxTrayType.SelectedIndex = Math.Min(Math.Max((int)Config.TrayBehavior, 0), comboBoxTrayType.Items.Count-1);
checkExpandLinks.Checked = Program.UserConfig.ExpandLinksOnHover;
checkTrayHighlight.Checked = Program.UserConfig.EnableTrayHighlight;
checkExpandLinks.Checked = Config.ExpandLinksOnHover;
checkSpellCheck.Checked = Config.EnableSpellCheck;
checkTrayHighlight.Checked = Config.EnableTrayHighlight;
}
private void checkExpandLinks_CheckedChanged(object sender, EventArgs e){
@@ -22,6 +23,13 @@ namespace TweetDck.Core.Other.Settings{
Config.ExpandLinksOnHover = checkExpandLinks.Checked;
}
private void checkSpellCheck_CheckedChanged(object sender, EventArgs e){
if (!Ready)return;
Config.EnableSpellCheck = checkSpellCheck.Checked;
PromptRestart();
}
private void comboBoxTrayType_SelectedIndexChanged(object sender, EventArgs e){
if (!Ready)return;

View File

@@ -8,14 +8,11 @@ namespace TweetDck.Core.Utils{
static class BrowserCache{
private static bool ClearOnExit { get; set; }
private static readonly string IndexFile = Path.Combine(Program.StoragePath,"index");
private static readonly string CacheFolder = Path.Combine(Program.StoragePath, "Cache");
private static IEnumerable<string> CacheFiles{
get{
return Directory.EnumerateFiles(Program.StoragePath).Where(path => {
string file = Path.GetFileName(path);
return file != null && (file.StartsWith("data_",StringComparison.Ordinal) || file.StartsWith("f_",StringComparison.Ordinal));
}).Concat(new[]{ IndexFile });
return Directory.EnumerateFiles(CacheFolder);
}
}
@@ -34,6 +31,21 @@ namespace TweetDck.Core.Utils{
task.Start();
}
public static void ClearOldCacheFiles(){
if (!Directory.Exists(CacheFolder)){
foreach(string file in Directory.EnumerateFiles(Program.StoragePath).Where(path => {
string file = Path.GetFileName(path);
return file != null && (file.StartsWith("data_", StringComparison.Ordinal) || file.StartsWith("f_", StringComparison.Ordinal));
}).Concat(new[]{ Path.Combine(Program.StoragePath, "index") })){
try{
File.Delete(file);
}catch{
// welp, too bad
}
}
}
}
public static void SetClearOnExit(){
ClearOnExit = true;
}

View File

@@ -33,7 +33,7 @@ namespace TweetDck.Core.Utils{
value = matchValue.Substring(indexEquals+1).Trim('"');
}
if (key != string.Empty){
if (key.Length != 0){
dictionary[key] = value;
++count;
}

View File

@@ -25,9 +25,6 @@ namespace TweetDck.Core.Utils{
public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("Shell32.dll")]
public static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern bool SetWindowPos(int hWnd, int hWndOrder, int x, int y, int width, int height, uint flags);

View File

@@ -0,0 +1,33 @@
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Security.Principal;
namespace TweetDck.Core.Utils{
static class WindowsUtils{
public static bool CheckFolderPermission(string path, FileSystemRights right){
try{
AuthorizationRuleCollection rules = Directory.GetAccessControl(path).GetAccessRules(true, true, typeof(SecurityIdentifier));
WindowsIdentity identity = WindowsIdentity.GetCurrent();
if (identity == null || identity.Groups == null){
return false;
}
bool accessAllow = false, accessDeny = false;
foreach(FileSystemAccessRule rule in rules.Cast<FileSystemAccessRule>().Where(rule => identity.Groups.Contains(rule.IdentityReference) && (right & rule.FileSystemRights) == right)){
switch(rule.AccessControlType){
case AccessControlType.Allow: accessAllow = true; break;
case AccessControlType.Deny: accessDeny = true; break;
}
}
return accessAllow && !accessDeny;
}
catch{
return false;
}
}
}
}

View File

@@ -1,42 +0,0 @@
using System;
using System.IO;
using Shell32;
namespace TweetDck.Migration.Helpers{
sealed class LnkEditor{
private readonly ShellLinkObject obj;
public LnkEditor(string file){
try{
Shell shell = new Shell();
Folder folder = shell.NameSpace(Path.GetDirectoryName(file));
FolderItem item = folder.Items().Item(Path.GetFileName(file));
obj = item.GetLink as ShellLinkObject;
}catch(Exception){
obj = null;
}
}
public void SetComment(string newComment){
if (obj == null)return;
obj.Description = newComment;
}
public void SetPath(string newPath){
if (obj == null)return;
obj.Path = newPath;
obj.SetIconLocation(newPath,0);
}
public void SetWorkingDirectory(string newWorkingDirectory){
if (obj == null)return;
obj.WorkingDirectory = newWorkingDirectory;
}
public void Save(){
if (obj == null)return;
obj.Save();
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
@@ -8,14 +7,28 @@ using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using TweetDck.Migration.Helpers;
using TweetDck.Core.Utils;
namespace TweetDck.Migration{
static class MigrationManager{
private static readonly string TweetDeckPathParent = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "twitter");
private static readonly string TweetDeckPath = Path.Combine(TweetDeckPathParent, "TweetDeck");
private static readonly string TweetDickStorage = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TweetDick");
public static void Run(){
if (!Program.IsPortable && Directory.Exists(TweetDickStorage) && !Directory.Exists(Program.StoragePath)){
if (MessageBox.Show("Welcome to TweetDuck! Would you like to move your old TweetDick configuration and login data?", "TweetDick Migration", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes){
try{
Directory.Move(TweetDickStorage, Program.StoragePath);
MessageBox.Show("All done! You can now uninstall TweetDick.", "TweetDick Migration", MessageBoxButtons.OK, MessageBoxIcon.Information);
}catch(Exception ex){
Program.Reporter.HandleException("Migration Error", "An unexpected error occurred during the migration process.", true, ex);
}
}
return;
}
if (!Program.UserConfig.IgnoreMigration && Directory.Exists(TweetDeckPath)){
MigrationDecision decision;
@@ -33,7 +46,7 @@ namespace TweetDck.Migration{
formWait.Close();
if (ex != null){
Program.HandleException("An unexpected exception has occurred during the migration process.",ex);
Program.Reporter.HandleException("Migration Error", "An unexpected error occurred during the migration process.", true, ex);
return;
}
@@ -121,36 +134,6 @@ namespace TweetDck.Migration{
}
if (decision == MigrationDecision.MigratePurge){
// update the lnk files wherever possible (desktop icons, pinned taskbar, start menu)
foreach(string location in GetLnkDirectories()){
if (string.IsNullOrEmpty(location))continue;
string linkFile = Path.Combine(location,"TweetDeck.lnk");
if (File.Exists(linkFile)){
LnkEditor lnk = new LnkEditor(linkFile);
lnk.SetPath(Application.ExecutablePath);
lnk.SetWorkingDirectory(Environment.CurrentDirectory);
lnk.SetComment(Program.BrandName+" client for Windows");
lnk.Save();
string renamed = Path.Combine(location,Program.BrandName+".lnk");
try{
if (!File.Exists(renamed)){
File.Move(linkFile,renamed);
}
else{
File.Delete(linkFile);
}
}catch{
// eh, too bad
}
}
}
NativeMethods.SHChangeNotify(0x8000000,0x1000,IntPtr.Zero,IntPtr.Zero); // refreshes desktop
// uninstall in the background
string guid = ProgramRegistrySearch.FindByDisplayName("TweetDeck");
@@ -179,12 +162,6 @@ namespace TweetDck.Migration{
}
}
private static IEnumerable<string> GetLnkDirectories(){
yield return Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
yield return Environment.GetFolderPath(Environment.SpecialFolder.CommonDesktopDirectory);
yield return Environment.ExpandEnvironmentVariables(@"%APPDATA%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar");
}
private static void RunUninstaller(string guid, int timeout){
Process uninstaller = Process.Start("msiexec.exe", "/x "+guid+" /quiet /qn");

View File

@@ -31,6 +31,7 @@
this.flowLayoutInfo = new System.Windows.Forms.FlowLayoutPanel();
this.labelWebsite = new System.Windows.Forms.Label();
this.labelVersion = new System.Windows.Forms.Label();
this.btnOpenConfig = new System.Windows.Forms.Button();
this.panelDescription.SuspendLayout();
this.flowLayoutInfo.SuspendLayout();
this.SuspendLayout();
@@ -38,9 +39,9 @@
// btnToggleState
//
this.btnToggleState.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnToggleState.Location = new System.Drawing.Point(449, 80);
this.btnToggleState.Location = new System.Drawing.Point(459, 80);
this.btnToggleState.Name = "btnToggleState";
this.btnToggleState.Size = new System.Drawing.Size(75, 23);
this.btnToggleState.Size = new System.Drawing.Size(65, 23);
this.btnToggleState.TabIndex = 0;
this.btnToggleState.Text = "Disable";
this.btnToggleState.UseVisualStyleBackColor = true;
@@ -99,7 +100,7 @@
this.flowLayoutInfo.Controls.Add(this.labelWebsite);
this.flowLayoutInfo.Location = new System.Drawing.Point(11, 85);
this.flowLayoutInfo.Name = "flowLayoutInfo";
this.flowLayoutInfo.Size = new System.Drawing.Size(432, 18);
this.flowLayoutInfo.Size = new System.Drawing.Size(368, 18);
this.flowLayoutInfo.TabIndex = 4;
this.flowLayoutInfo.WrapContents = false;
//
@@ -128,10 +129,22 @@
this.labelVersion.Text = "Version";
this.labelVersion.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// btnOpenConfig
//
this.btnOpenConfig.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnOpenConfig.Location = new System.Drawing.Point(385, 80);
this.btnOpenConfig.Name = "btnOpenConfig";
this.btnOpenConfig.Size = new System.Drawing.Size(68, 23);
this.btnOpenConfig.TabIndex = 6;
this.btnOpenConfig.Text = "Configure";
this.btnOpenConfig.UseVisualStyleBackColor = true;
this.btnOpenConfig.Click += new System.EventHandler(this.btnOpenConfig_Click);
//
// PluginControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.btnOpenConfig);
this.Controls.Add(this.flowLayoutInfo);
this.Controls.Add(this.panelDescription);
this.Controls.Add(this.labelName);
@@ -161,5 +174,6 @@
private System.Windows.Forms.FlowLayoutPanel flowLayoutInfo;
private System.Windows.Forms.Label labelWebsite;
private System.Windows.Forms.Label labelVersion;
private System.Windows.Forms.Button btnOpenConfig;
}
}

View File

@@ -1,5 +1,7 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using TweetDck.Core.Utils;
@@ -21,13 +23,10 @@ namespace TweetDck.Plugins.Controls{
this.labelVersion.Text = plugin.Version;
this.labelAuthor.Text = plugin.Author;
this.labelWebsite.Text = plugin.Website;
this.btnToggleState.Text = pluginManager.Config.IsEnabled(plugin) ? "Disable" : "Enable";
if (!plugin.CanRun){
this.labelName.ForeColor = Color.DarkRed;
this.btnToggleState.Enabled = false;
}
else if (labelDescription.Text == string.Empty){
UpdatePluginState();
if (labelDescription.Text.Length == 0){
labelDescription.Visible = false;
}
@@ -35,7 +34,7 @@ namespace TweetDck.Plugins.Controls{
}
private void panelDescription_Resize(object sender, EventArgs e){
if (labelDescription.Text == string.Empty){
if (labelDescription.Text.Length == 0){
Height = MinimumSize.Height;
}
else{
@@ -50,11 +49,38 @@ namespace TweetDck.Plugins.Controls{
}
}
private void btnOpenConfig_Click(object sender, EventArgs e){
using(Process.Start("explorer.exe", "/select,\""+plugin.ConfigPath+"\"")){}
}
private void btnToggleState_Click(object sender, EventArgs e){
bool newState = !pluginManager.Config.IsEnabled(plugin);
pluginManager.Config.SetEnabled(plugin, newState);
btnToggleState.Text = newState ? "Disable" : "Enable";
UpdatePluginState();
}
private void UpdatePluginState(){
bool isEnabled = plugin.CanRun && pluginManager.Config.IsEnabled(plugin);
Color textColor = isEnabled ? Color.Black : Color.FromArgb(90, 90, 90);
labelVersion.ForeColor = textColor;
labelAuthor.ForeColor = textColor;
labelWebsite.ForeColor = isEnabled ? Color.Blue : Color.FromArgb(90, 90, 249);
if (plugin.CanRun){
labelName.ForeColor = textColor;
labelDescription.ForeColor = textColor;
btnToggleState.Text = isEnabled ? "Disable" : "Enable";
btnOpenConfig.Visible = plugin.HasConfig;
btnOpenConfig.Enabled = btnOpenConfig.Visible && File.Exists(plugin.ConfigPath);
}
else{
labelName.ForeColor = Color.DarkRed;
labelDescription.ForeColor = Color.DarkRed;
btnToggleState.Visible = false;
btnOpenConfig.Visible = false;
}
}
}
}

View File

@@ -3,6 +3,11 @@ using TweetDck.Core.Utils;
namespace TweetDck.Plugins.Controls{
sealed partial class PluginListFlowLayout : FlowLayoutPanel{
public PluginListFlowLayout(){
FlowDirection = FlowDirection.TopDown;
WrapContents = false;
}
protected override void WndProc(ref Message m){
NativeMethods.ShowScrollBar(Handle, NativeMethods.SB_HORZ, false); // basically fuck the horizontal scrollbar very much
base.WndProc(ref m);

View File

@@ -12,6 +12,8 @@ namespace TweetDck.Plugins{
public string Author { get { return metadata["AUTHOR"]; } }
public string Version { get { return metadata["VERSION"]; } }
public string Website { get { return metadata["WEBSITE"]; } }
public string ConfigFile { get { return metadata["CONFIGFILE"]; } }
public string ConfigDefault { get { return metadata["CONFIGDEFAULT"]; } }
public string RequiredVersion { get { return metadata["REQUIRES"]; } }
public PluginGroup Group { get; private set; }
public PluginEnvironment Environments { get; private set; }
@@ -28,6 +30,30 @@ namespace TweetDck.Plugins{
}
}
public bool HasConfig{
get{
return ConfigFile.Length > 0 && GetFullPathIfSafe(ConfigFile).Length > 0;
}
}
public string ConfigPath{
get{
return HasConfig ? Path.Combine(path, ConfigFile) : string.Empty;
}
}
public bool HasDefaultConfig{
get{
return ConfigDefault.Length > 0 && GetFullPathIfSafe(ConfigDefault).Length > 0;
}
}
public string DefaultConfigPath{
get{
return HasDefaultConfig ? Path.Combine(path, ConfigDefault) : string.Empty;
}
}
private readonly string path;
private readonly string identifier;
private readonly Dictionary<string, string> metadata = new Dictionary<string, string>(4){
@@ -36,6 +62,8 @@ namespace TweetDck.Plugins{
{ "AUTHOR", "(anonymous)" },
{ "VERSION", "(unknown)" },
{ "WEBSITE", "" },
{ "CONFIGFILE", "" },
{ "CONFIGDEFAULT", "" },
{ "REQUIRES", "*" }
};
@@ -48,6 +76,18 @@ namespace TweetDck.Plugins{
this.Environments = PluginEnvironment.None;
}
private void OnMetadataLoaded(){
string configPath = ConfigPath, defaultConfigPath = DefaultConfigPath;
if (configPath.Length > 0 && defaultConfigPath.Length > 0 && !File.Exists(configPath) && File.Exists(defaultConfigPath)){
try{
File.Copy(defaultConfigPath, configPath, false);
}catch(Exception e){
Program.Reporter.HandleException("Plugin Loading Error", "Could not generate a configuration file for '"+identifier+"' plugin.", true, e);
}
}
}
public string GetScriptPath(PluginEnvironment environment){
if (Environments.HasFlag(environment)){
string file = environment.GetScriptFile();
@@ -58,6 +98,28 @@ namespace TweetDck.Plugins{
}
}
public string GetFullPathIfSafe(string relativePath){
string fullPath = Path.Combine(path, relativePath);
try{
string folderPathName = new DirectoryInfo(path).FullName;
DirectoryInfo currentInfo = new DirectoryInfo(fullPath);
while(currentInfo.Parent != null){
if (currentInfo.Parent.FullName == folderPathName){
return fullPath;
}
currentInfo = currentInfo.Parent;
}
}
catch{
// ignore
}
return string.Empty;
}
public override string ToString(){
return Identifier;
}
@@ -88,15 +150,7 @@ namespace TweetDck.Plugins{
private static bool LoadEnvironments(string path, Plugin plugin, out string error){
foreach(string file in Directory.EnumerateFiles(path, "*.js", SearchOption.TopDirectoryOnly).Select(Path.GetFileName)){
PluginEnvironment environment = PluginEnvironmentExtensions.Values.FirstOrDefault(env => file.Equals(env.GetScriptFile(),StringComparison.Ordinal));
if (environment != PluginEnvironment.None){
plugin.Environments |= environment;
}
else{
error = "Unknown script file: "+file;
return false;
}
plugin.Environments |= PluginEnvironmentExtensions.Values.FirstOrDefault(env => file.Equals(env.GetScriptFile(), StringComparison.Ordinal));
}
if (plugin.Environments == PluginEnvironment.None){
@@ -160,6 +214,8 @@ namespace TweetDck.Plugins{
return false;
}
plugin.OnMetadataLoaded();
error = string.Empty;
return true;
}

View File

@@ -20,30 +20,7 @@ namespace TweetDck.Plugins{
private string GetFullPathIfSafe(int token, string path){
Plugin plugin = manager.GetPluginFromToken(token);
if (plugin == null){
return string.Empty;
}
string fullPath = Path.Combine(plugin.FolderPath,path);
try{
string folderPathName = new DirectoryInfo(plugin.FolderPath).FullName;
DirectoryInfo currentInfo = new DirectoryInfo(fullPath);
while(currentInfo.Parent != null){
if (currentInfo.Parent.FullName == folderPathName){
return fullPath;
}
currentInfo = currentInfo.Parent;
}
}
catch{
// ignore
}
return string.Empty;
return plugin == null ? string.Empty : plugin.GetFullPathIfSafe(path);
}
public void WriteFile(int token, string path, string contents){
@@ -73,18 +50,34 @@ namespace TweetDck.Plugins{
return cachedContents;
}
try{
return fileCache[fullPath] = File.ReadAllText(fullPath, Encoding.UTF8);
}catch(FileNotFoundException){
throw new Exception("File not found.");
}catch(DirectoryNotFoundException){
throw new Exception("Directory not found.");
}
}
public void DeleteFile(int token, string path){
string fullPath = GetFullPathIfSafe(token, path);
if (fullPath == string.Empty){
if (fullPath.Length == 0){
throw new Exception("File path has to be relative to the plugin folder.");
}
fileCache.Remove(fullPath);
File.Delete(fullPath);
}
public bool CheckFileExists(int token, string path){
string fullPath = GetFullPathIfSafe(token, path);
if (fullPath.Length == 0){
throw new Exception("File path has to be relative to the plugin folder.");
}
return File.Exists(fullPath);
}
}
}

View File

@@ -4,7 +4,7 @@ using TweetDck.Plugins.Events;
namespace TweetDck.Plugins{
[Serializable]
class PluginConfig{
sealed class PluginConfig{
[field:NonSerialized]
public event EventHandler<PluginChangedStateEventArgs> PluginChangedState;
@@ -33,5 +33,9 @@ namespace TweetDck.Plugins{
public bool IsEnabled(Plugin plugin){
return !Disabled.Contains(plugin.Identifier) && plugin.CanRun;
}
public void DisableOfficialFromConfig(string pluginName){
Disabled.Add("official/"+pluginName);
}
}
}

View File

@@ -10,6 +10,7 @@ namespace TweetDck.Plugins{
class PluginManager{
public const string PluginBrowserScriptFile = "plugins.browser.js";
public const string PluginNotificationScriptFile = "plugins.notification.js";
public const string PluginGlobalScriptFile = "plugins.js";
public string PathOfficialPlugins { get { return Path.Combine(rootPath, "official"); } }
public string PathCustomPlugins { get { return Path.Combine(rootPath, "user"); } }
@@ -51,7 +52,6 @@ namespace TweetDck.Plugins{
}
public void Reload(){
HashSet<Plugin> prevPlugins = new HashSet<Plugin>(plugins);
plugins.Clear();
tokens.Clear();
@@ -65,7 +65,7 @@ namespace TweetDck.Plugins{
plugins.Add(plugin);
}
if (Reloaded != null && (loadErrors.Count > 0 || !prevPlugins.SetEquals(plugins))){
if (Reloaded != null){
Reloaded(this, new PluginLoadEventArgs(loadErrors));
}
}

View File

@@ -7,7 +7,7 @@ namespace TweetDck.Plugins{
}
public static string GeneratePlugin(string pluginIdentifier, string pluginContents, int pluginToken, PluginEnvironment environment){
StringBuilder build = new StringBuilder(pluginIdentifier.Length+pluginContents.Length+150);
StringBuilder build = new StringBuilder(2*pluginIdentifier.Length+pluginContents.Length+165);
build.Append("(function(").Append(environment.GetScriptVariables()).Append("){");
@@ -16,6 +16,7 @@ namespace TweetDck.Plugins{
build.Append("obj:new class extends PluginBase{").Append(pluginContents).Append("}");
build.Append("};");
build.Append("tmp.obj.$id=\"").Append(pluginIdentifier).Append("\";");
build.Append("tmp.obj.$token=").Append(pluginToken).Append(";");
build.Append("window.TD_PLUGINS.install(tmp);");

View File

@@ -1,8 +1,6 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Windows.Forms;
using CefSharp;
using TweetDck.Configuration;
@@ -14,29 +12,33 @@ using System.Threading;
using TweetDck.Plugins;
using TweetDck.Plugins.Events;
using TweetDck.Core.Other.Settings.Export;
using TweetDck.Core.Handling;
using System.Security.AccessControl;
[assembly: CLSCompliant(true)]
namespace TweetDck{
static class Program{
#if DUCK
public const string BrandName = "TweetDuck";
public const string Website = "http://tweetduck.chylex.com";
#else
public const string BrandName = "TweetDick";
public const string Website = "http://tweetdick.chylex.com";
#endif
public const string BrowserSubprocess = BrandName+".Browser.exe";
public const string VersionTag = "1.3.2";
public const string VersionFull = "1.3.2.0";
public const string VersionTag = "1.3.3";
public const string VersionFull = "1.3.3.0";
public static readonly Version Version = new Version(VersionTag);
public static readonly string StoragePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),BrandName);
public static readonly string PluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"plugins");
public static readonly string TemporaryPath = Path.Combine(Path.GetTempPath(),BrandName);
public static readonly bool IsPortable = File.Exists("makeportable");
public static readonly string ProgramPath = AppDomain.CurrentDomain.BaseDirectory;
public static readonly string StoragePath = IsPortable ? Path.Combine(ProgramPath, "portable", "storage") : GetDataStoragePath();
public static readonly string TemporaryPath = IsPortable ? Path.Combine(ProgramPath, "portable", "tmp") : Path.Combine(Path.GetTempPath(), BrandName+'_'+Path.GetRandomFileName().Substring(0, 6));
public static readonly string ConfigFilePath = Path.Combine(StoragePath, "TD_UserConfig.cfg");
private static readonly string LogFilePath = Path.Combine(StoragePath, "TD_Log.txt");
public static readonly string ScriptPath = Path.Combine(ProgramPath, "scripts");
public static readonly string PluginPath = Path.Combine(ProgramPath, "plugins");
public static uint WindowRestoreMessage;
@@ -44,12 +46,7 @@ namespace TweetDck{
private static bool HasCleanedUp;
public static UserConfig UserConfig { get; private set; }
public static string LogFile{
get{
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"td-log.txt");
}
}
public static Reporter Reporter { get; private set; }
[STAThread]
private static void Main(){
@@ -58,14 +55,29 @@ namespace TweetDck{
WindowRestoreMessage = NativeMethods.RegisterWindowMessage("TweetDuckRestore");
if (!WindowsUtils.CheckFolderPermission(ProgramPath, FileSystemRights.WriteData)){
MessageBox.Show(BrandName+" does not have write permissions to the program folder. If it is installed in Program Files, please run it as Administrator.", "Administrator Required", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
Reporter = new Reporter(LogFilePath);
AppDomain.CurrentDomain.UnhandledException += (sender, args) => {
Exception ex = args.ExceptionObject as Exception;
if (ex != null){
Reporter.HandleException(BrandName+" Has Failed :(", "An unhandled exception has occurred.", false, ex);
}
};
string[] programArguments = Environment.GetCommandLineArgs();
if (programArguments.Contains("-restart")){
for(int attempt = 0; attempt < 21; attempt++){
for(int attempt = 0; attempt < 41; attempt++){
if (LockManager.Lock()){
break;
}
else if (attempt == 20){
else if (attempt == 40){
MessageBox.Show(BrandName+" is taking too long to close, please wait and then start the application again manually.", BrandName+" Cannot Restart", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
@@ -73,15 +85,20 @@ namespace TweetDck{
Thread.Sleep(500);
}
}
ReloadConfig();
}
else{
ReloadConfig();
MigrationManager.Run();
if (!LockManager.Lock()){
if (LockManager.LockingProcess.MainWindowHandle == IntPtr.Zero && LockManager.LockingProcess.Responding){ // restore if the original process is in tray
NativeMethods.SendMessage(NativeMethods.HWND_BROADCAST, WindowRestoreMessage, 0, IntPtr.Zero);
return;
}
else if (MessageBox.Show("Another instance of "+BrandName+" is already running.\r\nDo you want to close it?", BrandName+" is Already Running", MessageBoxButtons.YesNo, MessageBoxIcon.Error, MessageBoxDefaultButton.Button2) == DialogResult.Yes){
if (!LockManager.CloseLockingProcess(10000)){
if (!LockManager.CloseLockingProcess(20000)){
MessageBox.Show("Could not close the other process.", BrandName+" Has Failed :(", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
@@ -92,33 +109,16 @@ namespace TweetDck{
}
}
if (programArguments.Contains("-importcookies") && File.Exists(ExportManager.TempCookiesPath)){
try{
if (File.Exists(ExportManager.CookiesPath)){
File.Delete(ExportManager.CookiesPath);
if (programArguments.Contains("-importcookies")){
ExportManager.ImportCookies();
}
File.Move(ExportManager.TempCookiesPath,ExportManager.CookiesPath);
}catch(Exception e){
HandleException("Could not import the cookie file to restore login session.",e);
}
}
ReloadConfig();
MigrationManager.Run();
Cef.OnContextInitialized = () => {
using(IRequestContext ctx = Cef.GetGlobalRequestContext()){
string err;
ctx.SetPreference("browser.enable_spellchecking",false,out err);
}
};
BrowserCache.ClearOldCacheFiles();
CefSettings settings = new CefSettings{
AcceptLanguageList = BrowserUtils.HeaderAcceptLanguage,
UserAgent = BrowserUtils.HeaderUserAgent,
Locale = CultureInfo.CurrentCulture.TwoLetterISOLanguageName,
Locale = GetCmdArgumentValue("locale") ?? "en",
CachePath = StoragePath,
BrowserSubprocessPath = File.Exists(BrowserSubprocess) ? BrowserSubprocess : "CefSharp.BrowserSubprocess.exe",
#if !DEBUG
@@ -128,15 +128,7 @@ namespace TweetDck{
CommandLineArgsParser.AddToDictionary(UserConfig.CustomCefArgs, settings.CefCommandLineArgs);
Cef.Initialize(settings);
AppDomain.CurrentDomain.UnhandledException += (sender, args) => {
Exception ex = args.ExceptionObject as Exception;
if (ex != null){
HandleException("An unhandled exception has occurred.",ex);
}
};
Cef.Initialize(settings, false, new BrowserProcessHandler());
Application.ApplicationExit += (sender, args) => ExitCleanup();
@@ -162,28 +154,21 @@ namespace TweetDck{
}
}
public static void HandleException(string message, Exception e){
Log(e.ToString());
private static string GetCmdArgumentValue(string search){
string[] args = Environment.GetCommandLineArgs();
int index = Array.FindIndex(args, arg => arg.Equals(search, StringComparison.OrdinalIgnoreCase));
if (MessageBox.Show(message+"\r\nDo you want to open the log file to report the issue?",BrandName+" Has Failed :(",MessageBoxButtons.YesNo,MessageBoxIcon.Error,MessageBoxDefaultButton.Button2) == DialogResult.Yes){
Process.Start(LogFile);
}
return index >= 0 && index < args.Length-1 ? args[index+1] : null;
}
public static void Log(string data){
StringBuilder build = new StringBuilder();
private static string GetDataStoragePath(){
string custom = GetCmdArgumentValue("-datafolder");
if (!File.Exists(LogFile)){
build.Append("Please, report all issues to: https://github.com/chylex/TweetDuck/issues\r\n\r\n");
if (custom != null && (custom.Contains(Path.DirectorySeparatorChar) || custom.Contains(Path.AltDirectorySeparatorChar))){
return custom;
}
build.Append("[").Append(DateTime.Now.ToString("G")).Append("]\r\n");
build.Append(data).Append("\r\n\r\n");
try{
File.AppendAllText(LogFile,build.ToString(),Encoding.UTF8);
}catch{
// oops
else{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), custom ?? BrandName);
}
}
@@ -196,7 +181,7 @@ namespace TweetDck{
File.Delete(ConfigFilePath);
File.Delete(UserConfig.GetBackupFile(ConfigFilePath));
}catch(Exception e){
HandleException("Could not delete configuration files to reset the settings.",e);
Reporter.HandleException("Configuration Reset Error", "Could not delete configuration files to reset the settings.", true, e);
return;
}

View File

@@ -1,13 +1,11 @@
# Build Instructions
The program was build using Visual Studio 2013. After opening the solution, make sure you have **CefSharp.WinForms** and **Microsoft.VC120.CRT.JetBrains** included - if not, download them using NuGet. For **CefSharp**, you will need version 49 or newer currently available as a pre-release.
The program was build using Visual Studio 2013. After opening the solution, make sure you have **CefSharp.WinForms** and **Microsoft.VC120.CRT.JetBrains** included - if not, download them using NuGet. For **CefSharp**, you will need version 53 or newer currently available as a pre-release.
```
PM> Install-Package CefSharp.WinForms -Pre
PM> Install-Package CefSharp.WinForms -Pre -Version 53.0.0-pre01
PM> Install-Package Microsoft.VC120.CRT.JetBrains
```
TweetD\*ck comes in two variants - TweetDick and TweetDuck. The solution includes both configurations under the names **Release Dick** and **Release Duck**, so make sure to select the correct one, or build both using Batch Build.
After building, run **_postbuild.bat** which deletes unnecessary files that CefSharp adds after post-build events >_>
Built files are then available in **bin/x86** and/or **bin/x64**.

74
Reporter.cs Normal file
View File

@@ -0,0 +1,74 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Text;
using System.Windows.Forms;
using TweetDck.Core.Other;
namespace TweetDck{
class Reporter{
private readonly string logFile;
public Reporter(string logFile){
this.logFile = logFile;
}
public bool Log(string data){
StringBuilder build = new StringBuilder();
if (!File.Exists(logFile)){
build.Append("Please, report all issues to: https://github.com/chylex/TweetDuck/issues\r\n\r\n");
}
build.Append("[").Append(DateTime.Now.ToString("G", CultureInfo.CurrentCulture)).Append("]\r\n");
build.Append(data).Append("\r\n\r\n");
try{
File.AppendAllText(logFile, build.ToString(), Encoding.UTF8);
return true;
}catch{
return false;
}
}
public void HandleException(string caption, string message, bool canIgnore, Exception e){
Log(e.ToString());
FormMessage form = new FormMessage(caption, message+"\r\nError: "+e.Message, canIgnore ? MessageBoxIcon.Warning : MessageBoxIcon.Error);
form.AddButton("Exit");
Button btnIgnore = form.AddButton("Ignore");
Button btnOpenLog = new Button{
Anchor = AnchorStyles.Bottom | AnchorStyles.Left,
Location = new Point(12, 12),
Margin = new Padding(0, 0, 48, 0),
Size = new Size(88, 26),
Text = "Show Error Log",
UseVisualStyleBackColor = true
};
btnOpenLog.Click += (sender, args) => Process.Start(logFile);
form.AddActionControl(btnOpenLog);
if (!canIgnore){
btnIgnore.Enabled = false;
}
if (form.ShowDialog() == DialogResult.OK){
if (form.ClickedButton == btnIgnore){
return;
}
}
try{
Process.GetCurrentProcess().Kill();
}catch{
Environment.FailFast(message, e);
}
}
}
}

View File

@@ -0,0 +1,14 @@
[name]
Clear columns
[description]
- Adds buttons and keyboard shortcuts to quickly clear columns
[author]
chylex
[version]
1.0
[website]
https://tweetduck.chylex.com

View File

@@ -0,0 +1,92 @@
constructor(){
super({
requiresPageReload: true
});
}
enabled(){
// prepare variables and functions
var clearColumn = (columnName) => {
TD.controller.columnManager.get(columnName).clear();
TD.controller.stats.columnActionClick("clear");
};
var clearAllColumns = () => {
Object.keys(TD.controller.columnManager.getAll()).forEach(key => clearColumn(key));
};
var replaceMustache = (key, search, replace) => {
TD.mustaches[key] = TD.mustaches[key].replace(search, replace);
};
// prepare event handlers
this.eventClearSingle = function(){
clearColumn($(this).closest(".js-column").attr("data-column"));
};
this.eventClearAll = function(){
clearAllColumns();
};
this.eventKeys = function(e){
if (e.keyCode === 46 && (document.activeElement === null || document.activeElement === document.body)){ // 46 = delete
if (e.altKey){
clearAllColumns();
}
else{
var focusedColumn = $(".js-column.is-focused");
if (focusedColumn.length){
clearColumn(focusedColumn.attr("data-column"));
}
}
}
};
// add column buttons and keyboard shortcut info to UI
replaceMustache("column/column_header.mustache", "</header>", [
'{{^isTemporary}}',
'<a class="column-header-link" href="#" data-action="td-clearcolumns-dosingle" style="right:34px">',
'<i class="icon icon-clear-timeline"></i>',
'</a>',
'{{/isTemporary}}',
'</header>'
].join(""));
replaceMustache("keyboard_shortcut_list.mustache", "</dl> <dl", [
'<dd class="keyboard-shortcut-definition" style="white-space:nowrap">',
'<span class="text-like-keyboard-key">1</span> … <span class="text-like-keyboard-key">9</span> + <span class="text-like-keyboard-key">Del</span> Clear column 19',
'</dd><dd class="keyboard-shortcut-definition">',
'<span class="text-like-keyboard-key">Alt</span> + <span class="text-like-keyboard-key">Del</span> Clear all',
'</dd></dl><dl'
].join(""));
// load custom style
var style = document.createElement("style");
document.head.appendChild(style);
var sheet = style.sheet;
sheet.insertRule(".column-title { margin-right: 60px !important; }", 0);
sheet.insertRule(".column-type-message .column-title { margin-right: 115px !important; }", 0);
sheet.insertRule(".mark-all-read-link { right: 59px !important; }", 0);
sheet.insertRule(".open-compose-dm-link { right: 90px !important; }", 0);
}
ready(){
// setup events
$(document).on("click", "[data-action='td-clearcolumns-dosingle']", this.eventClearSingle);
$(document).on("click", "[data-action='td-clearcolumns-doall']", this.eventClearAll);
$(document).on("keydown", this.eventKeys);
// add clear all button
$("nav.app-navigator").first().append([
'<a class="link-clean cf app-nav-link padding-hl" data-title="Clear all" data-action="td-clearcolumns-doall">',
'<div class="obj-left"><i class="icon icon-large icon-clear-timeline"></i></div>',
'<div class="nbfc padding-ts hide-condensed">Clear all</div>',
'</a></nav>'
].join(""));
}
disabled(){
// not needed, plugin reloads the page when enabled or disabled
}

View File

@@ -12,4 +12,4 @@ chylex
1.0
[website]
http://tweetduck.chylex.com
https://tweetduck.chylex.com

View File

@@ -0,0 +1,23 @@
[name]
Custom reply account
[description]
- Allows customizing the automatically selected reply account per column
[author]
chylex
[version]
1.0
[website]
https://tweetduck.chylex.com
[configfile]
configuration.js
[configdefault]
configuration.default.js
[requires]
1.3.3

View File

@@ -0,0 +1,67 @@
enabled(){
var configuration = { defaultAccount: "" };
window.TDPF_loadConfigurationFile(this, "configuration.js", "configuration.default.js", obj => configuration = obj);
this.uiInlineComposeTweetEvent = function(e, data){
var account = null;
if (configuration.useAdvancedSelector && configuration.customSelector){
var column = TD.controller.columnManager.get(data.element.closest("section.column").attr("data-column"));
var result = configuration.customSelector(column);
if (typeof result === "string" && result[0] === '@'){
account = result.substring(1);
}
}
if (account === null){
if (configuration.defaultAccount === false){
return;
}
else if (configuration.defaultAccount !== "" && configuration.defaultAccount[0] === '@'){
account = configuration.defaultAccount.substring(1);
}
}
var identifier;
if (account === null){
identifier = TD.storage.clientController.client.getDefaultAccount();
}
else{
var obj = TD.storage.accountController.getAccountFromUsername(account);
if (obj.length === 0){
return;
}
else{
identifier = obj[0].privateState.key;
}
}
data.singleFrom = data.from = [ identifier ];
};
}
ready(){
var events = $._data(document, "events");
if ("uiInlineComposeTweet" in events){
$(document).on("uiInlineComposeTweet", this.uiInlineComposeTweetEvent);
var handlers = events["uiInlineComposeTweet"];
var oldHandler = handlers[0];
var newHandler = handlers[1];
handlers[0] = newHandler;
handlers[1] = oldHandler;
}
else{
$(document).on("uiInlineComposeTweet", this.uiInlineComposeTweetEvent);
}
}
disabled(){
$(document).off("uiInlineComposeTweet", this.uiInlineComposeTweetEvent);
}

View File

@@ -0,0 +1,79 @@
{
/*
* WARNING
* -------
*
* Make sure you are editing 'configuration.js' and not the default configuration file, as the default one will be replaced with each update.
*
*/
/*
* Simple way of configuring the plugin
* ------------------------------------
*
* Set value of 'defaultAccount' to one of the following values:
*
* "" to use your preferred TweetDeck account for all replies (default)
* "@myAccount" to specify an account name to use; has to be one of your registered account names
* false to fall back to default TweetDeck behavior; useful for advanced configuration below, otherwise disable the plugin instead
*
*/
defaultAccount: "",
/*
* Advanced way of configuring the plugin
* --------------------------------------
*
* This assumes a basic knowledge of JavaScript and jQuery.
*
* 1. Set value of 'useAdvancedSelector' to true
* 2. Uncomment the 'customSelector' function, and replace the example code with your desired behavior
*
* If 'customSelector' returns a string containing a full name of one of the registered accounts (including @), that account is used.
* If it returns anything else (for example false, undefined, or an account name that is not registered), it falls back to 'defaultAccount' behavior.
*
* The 'column' parameter is a TweetDeck column object. If you want to see all properties of the object, open your browser, nagivate to TweetDeck,
* log in, and run the following code in your browser console, which will return an object containing all of the column objects mapped to their IDs:
* TD.controller.columnManager.getAll()
*
* The example below shows how to extract the column type, title, and account from the object.
* Column type is prefixed with col_, and may be one of the following:
*
* col_timeline, col_interactions, col_mentions, col_followers, col_search, col_list,
* col_customtimeline, col_messages, col_usertweets, col_favorites, col_activity,
* col_dataminr, col_home, col_me, col_inbox, col_scheduled, col_unknown
*
* Some of these appear to be unused (for example, Home columns are 'col_timeline' instead of 'col_home').
*
* If you want to see your column types, run this in your browser console:
* Object.values(TD.controller.columnManager.getAll()).forEach(obj => console.log(obj.getColumnType()));
*
* You can also get the jQuery column object using: $("section.column[data-column='"+column.ui.state.columnKey+"']")
*
*/
useAdvancedSelector: false,
/*customSelector: function(column){
var titleObj = $(column.getTitleHTML());
var columnType = column.getColumnType(); // col_timeline
var columnTitle = titleObj.siblings(".column-head-title").text(); // Home
var columnAccount = titleObj.siblings(".attribution").text(); // @chylexmc
if (columnType === "col_search" && columnTitle === "TweetDuck"){
// This is a search column that looks for 'TweetDuck' in the tweets,
// search columns are normally linked to the preferred account
// so this forces the @TryTweetDuck account to be used instead.
return "@TryTweetDuck";
}
else if (columnType === "col_timeline" && columnAccount === "@chylexcz"){
// This is a Home column of my test account @chylexcz,
// but I want to reply to tweets from my official account.
return "@chylexmc";
}
// otherwise returns 'undefined' which falls back to 'defaultAccount' behavior
}*/
}

View File

@@ -11,7 +11,7 @@ namespace TweetDck.Resources{
public static string LoadResource(string name){
try{
return File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,name),Encoding.UTF8);
return File.ReadAllText(Path.Combine(Program.ScriptPath, name), Encoding.UTF8);
}catch(Exception ex){
MessageBox.Show("Unfortunately, "+Program.BrandName+" could not load the "+name+" file. The program will continue running with limited functionality.\r\n\r\n"+ex.Message, Program.BrandName+" Has Failed :(", MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;

View File

@@ -397,6 +397,21 @@
}
};
//
// Block: Fix scheduled tweets not showing up sometimes.
//
$(document).on("dataTweetSent", function(e, data){
if (data.response.state && data.response.state === "scheduled"){
var column = Object.values(TD.controller.columnManager.getAll()).find(column => column.model.state.type === "scheduled");
if (column){
setTimeout(function(){
column.reloadTweets();
}, 1000);
}
}
});
//
// Block: Inject custom CSS and layout into the page.
//
@@ -407,6 +422,7 @@
styleOfficial.sheet.insertRule("a[data-full-url] { word-break: break-all; }", 0); // break long urls
styleOfficial.sheet.insertRule(".column-nav-link .attribution { position: absolute; }", 0); // fix cut off account names
styleOfficial.sheet.insertRule(".txt-base-smallest .badge-verified:before { height: 13px !important; }", 0); // fix cut off badge icon
styleOfficial.sheet.insertRule(".keyboard-shortcut-list { vertical-align: top; }", 0); // fix keyboard navigation alignment
if ($TD.hasCustomBrowserCSS){
var styleCustom = document.createElement("style");

View File

@@ -0,0 +1,37 @@
(function($TDP){
//
// Block: Setup a simple JavaScript object configuration loader.
//
window.TDPF_loadConfigurationFile = function(pluginObject, fileNameUser, fileNameDefault, onSuccess, onFailure){
var identifier = pluginObject.$id;
var token = pluginObject.$token;
$TDP.checkFileExists(token, fileNameUser).then(exists => {
var fileName = exists ? fileNameUser : fileNameDefault;
$TDP.readFile(token, fileName, true).then(contents => {
var obj;
try{
obj = eval("("+contents+")");
}catch(err){
if (!(onFailure && onFailure(err.message))){
$TD.alert("warning", "Problem loading '"+fileName+"' file for '"+identifier+"' plugin, the JavaScript syntax is invalid: "+err.message);
}
return;
}
onSuccess && onSuccess(obj);
}).catch(err => {
if (!(onFailure && onFailure(err))){
$TD.alert("warning", "Problem loading '"+fileName+"' file for '"+identifier+"' plugin: "+err.message);
}
});
}).catch(err => {
if (!(onFailure && onFailure(err))){
$TD.alert("warning", "Problem checking '"+fileNameUser+"' file for '"+identifier+"' plugin: "+err.message);
}
});
};
})($TDP);

View File

@@ -18,6 +18,9 @@
// Function: Creates the update notification element. Removes the old one if already exists.
//
var createUpdateNotificationElement = function(version, download){
var outdated = version === "unsupported";
var tweetdick = version === "tweetdick";
var ele = $("#tweetdck-update");
var existed = ele.length > 0;
@@ -25,13 +28,31 @@
ele.remove();
}
var html = [
var html = outdated ? [
"<div id='tweetdck-update'>",
"<p class='tdu-title'>Unsupported System</p>",
"<p class='tdu-info'>You will not receive updates.</p>",
"<div class='tdu-buttons'>",
"<button class='btn btn-positive tdu-btn-unsupported'><span class='label'>Read More</span></button>",
"<button class='btn btn-negative tdu-btn-dismiss'><span class='label'>Dismiss</span></button>",
"</div>",
"</div>"
] : tweetdick ? [
"<div id='tweetdck-update'>",
"<p class='tdu-title'>TweetDick Ending</p>",
"<p class='tdu-info'>Please, move to TweetDuck.</p>",
"<div class='tdu-buttons'>",
"<button class='btn btn-positive tdu-btn-unsupported'><span class='label'>Read More</span></button>",
"<button class='btn btn-negative tdu-btn-dismiss'><span class='label'>Dismiss</span></button>",
"</div>",
"</div>"
] : [
"<div id='tweetdck-update'>",
"<p class='tdu-title'>"+$TDU.brandName+" Update</p>",
"<p class='tdu-info'>Version "+version+" is now available.</p>",
"<div class='tdu-buttons'>",
"<button class='btn btn-positive tdu-btn-download'><span class='label'>Download</button>",
"<button class='btn btn-negative tdu-btn-dismiss'><span class='label'>Dismiss</button>",
"<button class='btn btn-positive tdu-btn-download'><span class='label'>Download</span></button>",
"<button class='btn btn-negative tdu-btn-dismiss'><span class='label'>Dismiss</span></button>",
"</div>",
"</div>"
];
@@ -60,7 +81,7 @@
fontWeight: "bold",
textAlign: "center",
letterSpacing: "0.2px",
margin: "4px auto 2px"
margin: "5px auto 2px"
});
ele.children("p.tdu-info").first().css({
@@ -93,7 +114,15 @@
$TDU.onUpdateAccepted(version, download);
});
buttonDiv.children(".tdu-btn-dismiss").click(function(){
buttonDiv.children(".tdu-btn-unsupported").click(function(){
$TDU.openBrowser("https://github.com/chylex/TweetDuck/wiki/Supported-Systems");
});
buttonDiv.children(".tdu-btn-tweetdick").click(function(){
$TDU.openBrowser("https://github.com/chylex/TweetDick/wiki/Future-of-TweetDick");
});
buttonDiv.children(".tdu-btn-dismiss,.tdu-btn-unsupported").click(function(){
$TDU.onUpdateDismissed(version);
ele.slideUp(function(){ ele.remove(); });
});
@@ -109,6 +138,21 @@
// Function: Runs an update check and updates all DOM elements appropriately.
//
var runUpdateCheck = function(force, eventID){
if (!$TDU.isSystemSupported){
if ($TDU.dismissedVersionTag !== "unsupported"){
createUpdateNotificationElement("unsupported");
}
return;
}
else if ($TDU.brandName === "TweetDick"){
if ($TDU.dismissedVersionTag !== "tweetdick"){
createUpdateNotificationElement("tweetdick");
}
return;
}
clearTimeout(updateCheckTimeoutID);
updateCheckTimeoutID = setTimeout(runUpdateCheck, 1000*60*60); // 1 hour

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.props" Condition="Exists('packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.props')" />
<Import Project="packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.props" Condition="Exists('packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.props')" />
<Import Project="packages\CefSharp.WinForms.49.0.0-pre02\build\CefSharp.WinForms.props" Condition="Exists('packages\CefSharp.WinForms.49.0.0-pre02\build\CefSharp.WinForms.props')" />
<Import Project="packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.props" Condition="Exists('packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
@@ -11,12 +13,12 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TweetDck</RootNamespace>
<AssemblyName Condition=" '$(Configuration)' == 'Debug' ">TweetDick</AssemblyName>
<AssemblyName Condition=" '$(Configuration)' == 'Release Dick' ">TweetDick</AssemblyName>
<AssemblyName Condition=" '$(Configuration)' == 'Release Duck' ">TweetDuck</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<AssemblyName Condition=" '$(Configuration)' == 'Release' ">TweetDuck</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<NuGetPackageImportStamp>ff8ce4f3</NuGetPackageImportStamp>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<NuGetPackageImportStamp>e83161d1</NuGetPackageImportStamp>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
@@ -41,24 +43,13 @@
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Dick|x86' ">
<OutputPath>bin\x86\Release Dick\</OutputPath>
<DefineConstants>
</DefineConstants>
<Optimize>true</Optimize>
<DebugType>none</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<UseVSHostingProcess>false</UseVSHostingProcess>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Resources\icon.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Duck|x86' ">
<OutputPath>bin\x86\Release Duck\</OutputPath>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\x86\Release\</OutputPath>
<Optimize>true</Optimize>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
@@ -66,7 +57,12 @@
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<DefineConstants>DUCK</DefineConstants>
<DefineConstants>
</DefineConstants>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<AssemblyName>TweetDuck</AssemblyName>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@@ -99,6 +95,7 @@
<Compile Include="Core\Controls\TabPanel.Designer.cs">
<DependentUpon>TabPanel.cs</DependentUpon>
</Compile>
<Compile Include="Core\Handling\BrowserProcessHandler.cs" />
<Compile Include="Core\Handling\ContextMenuBase.cs" />
<Compile Include="Core\Handling\ContextMenuBrowser.cs" />
<Compile Include="Core\FormBrowser.cs">
@@ -123,6 +120,12 @@
<Compile Include="Core\Other\FormAbout.Designer.cs">
<DependentUpon>FormAbout.cs</DependentUpon>
</Compile>
<Compile Include="Core\Other\FormMessage.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Core\Other\FormMessage.Designer.cs">
<DependentUpon>FormMessage.cs</DependentUpon>
</Compile>
<Compile Include="Core\Other\FormPlugins.cs">
<SubType>Form</SubType>
</Compile>
@@ -175,6 +178,7 @@
</Compile>
<Compile Include="Core\Utils\CommandLineArgsParser.cs" />
<Compile Include="Core\Utils\WindowState.cs" />
<Compile Include="Core\Utils\WindowsUtils.cs" />
<Compile Include="Migration\FormBackgroundWork.cs">
<SubType>Form</SubType>
</Compile>
@@ -209,6 +213,7 @@
<Compile Include="Plugins\Events\PluginLoadEventArgs.cs" />
<Compile Include="Plugins\PluginManager.cs" />
<Compile Include="Plugins\PluginScriptGenerator.cs" />
<Compile Include="Reporter.cs" />
<Compile Include="Updates\FormUpdateDownload.cs">
<SubType>Form</SubType>
</Compile>
@@ -235,7 +240,6 @@
<Compile Include="Migration\FormMigrationQuestion.Designer.cs">
<DependentUpon>FormMigrationQuestion.cs</DependentUpon>
</Compile>
<Compile Include="Migration\Helpers\LnkEditor.cs" />
<Compile Include="Migration\MigrationDecision.cs" />
<Compile Include="Migration\MigrationManager.cs" />
<Compile Include="Migration\Helpers\ProgramRegistrySearch.cs" />
@@ -272,17 +276,6 @@
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<COMReference Include="Shell32">
<Guid>{50A7E9B0-70EF-11D1-B75A-00A0C90564FE}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Core\FormBrowser.resx">
<DependentUpon>FormBrowser.cs</DependentUpon>
@@ -310,36 +303,6 @@
<TargetPath>icon.ico</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Resources\Scripts\code.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>code.js</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Resources\Scripts\notification.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>notification.js</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Resources\Scripts\plugins.browser.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>plugins.browser.js</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Resources\Scripts\plugins.notification.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>plugins.notification.js</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ContentWithTargetPath Include="Resources\Scripts\update.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>update.js</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<None Include="Resources\icon-small.ico" />
<None Include="Resources\icon-tray-new.ico" />
@@ -347,21 +310,20 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\Plugins\" />
<Folder Include="Resources\Scripts\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\cef.redist.x86.3.2623.1396\build\cef.redist.x86.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x86.3.2623.1396\build\cef.redist.x86.targets'))" />
<Error Condition="!Exists('packages\cef.redist.x64.3.2623.1396\build\cef.redist.x64.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x64.3.2623.1396\build\cef.redist.x64.targets'))" />
<Error Condition="!Exists('packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.49.0.0-pre02\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.49.0.0-pre02\build\CefSharp.WinForms.props'))" />
<Error Condition="!Exists('packages\cef.redist.x86.3.2785.1478\build\cef.redist.x86.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x86.3.2785.1478\build\cef.redist.x86.targets'))" />
<Error Condition="!Exists('packages\cef.redist.x64.3.2785.1478\build\cef.redist.x64.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\cef.redist.x64.3.2785.1478\build\cef.redist.x64.targets'))" />
<Error Condition="!Exists('packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.props'))" />
<Error Condition="!Exists('packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.targets'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.props'))" />
<Error Condition="!Exists('packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.targets'))" />
</Target>
<Import Project="packages\cef.redist.x86.3.2623.1396\build\cef.redist.x86.targets" Condition="Exists('packages\cef.redist.x86.3.2623.1396\build\cef.redist.x86.targets')" />
<Import Project="packages\cef.redist.x64.3.2623.1396\build\cef.redist.x64.targets" Condition="Exists('packages\cef.redist.x64.3.2623.1396\build\cef.redist.x64.targets')" />
<Import Project="packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.49.0.0-pre02\build\CefSharp.Common.targets')" />
<PropertyGroup>
<PostBuildEvent>del "$(TargetPath).config"
xcopy "$(ProjectDir)LICENSE.md" "$(TargetDir)" /Y
@@ -370,6 +332,10 @@ ren "$(TargetDir)LICENSE.md" "LICENSE.txt"
xcopy "$(ProjectDir)Libraries\CEFSHARP-LICENSE.txt" "$(TargetDir)" /Y
xcopy "$(ProjectDir)packages\Microsoft.VC120.CRT.JetBrains.12.0.21005.2\DotFiles\msvcp120.dll" "$(TargetDir)" /Y
xcopy "$(ProjectDir)packages\Microsoft.VC120.CRT.JetBrains.12.0.21005.2\DotFiles\msvcr120.dll" "$(TargetDir)" /Y
rmdir "$(TargetDir)scripts"
mkdir "$(TargetDir)scripts"
xcopy "$(ProjectDir)Resources\Scripts\*" "$(TargetDir)scripts\" /E /Y
rmdir "$(TargetDir)plugins"
mkdir "$(TargetDir)plugins"
mkdir "$(TargetDir)plugins\official"
mkdir "$(TargetDir)plugins\user"
@@ -377,6 +343,10 @@ xcopy "$(ProjectDir)Resources\Plugins\*" "$(TargetDir)plugins\official\" /E /Y
rmdir "$(ProjectDir)\bin\Debug"
rmdir "$(ProjectDir)\bin\Release"</PostBuildEvent>
</PropertyGroup>
<Import Project="packages\cef.redist.x86.3.2785.1478\build\cef.redist.x86.targets" Condition="Exists('packages\cef.redist.x86.3.2785.1478\build\cef.redist.x86.targets')" />
<Import Project="packages\cef.redist.x64.3.2785.1478\build\cef.redist.x64.targets" Condition="Exists('packages\cef.redist.x64.3.2785.1478\build\cef.redist.x64.targets')" />
<Import Project="packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.53.0.0-pre01\build\CefSharp.Common.targets')" />
<Import Project="packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.targets" Condition="Exists('packages\CefSharp.WinForms.53.0.0-pre01\build\CefSharp.WinForms.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@@ -1,4 +1,4 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.40629.0
@@ -8,17 +8,14 @@ EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release Dick|x86 = Release Dick|x86
Release Duck|x86 = Release Duck|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|x86.ActiveCfg = Debug|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|x86.Build.0 = Debug|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Debug|x86.Deploy.0 = Debug|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release Dick|x86.ActiveCfg = Release Dick|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release Dick|x86.Build.0 = Release Dick|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release Duck|x86.ActiveCfg = Release Duck|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release Duck|x86.Build.0 = Release Duck|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release|x86.ActiveCfg = Release|x86
{2389A7CD-E0D3-4706-8294-092929A33A2D}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -90,7 +90,7 @@ namespace TweetDck.Updates{
}
}
else if (e.Error != null){
Program.Log(e.Error.ToString());
Program.Reporter.Log(e.Error.ToString());
if (MessageBox.Show("Could not download the update: "+e.Error.Message+"\r\n\r\nDo you want to open the website and try downloading the update manually?", "Update Has Failed", MessageBoxButtons.YesNo, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1) == DialogResult.Yes){
BrowserUtils.OpenExternalBrowser(Program.Website);

View File

@@ -3,6 +3,7 @@ using CefSharp;
using CefSharp.WinForms;
using TweetDck.Core;
using TweetDck.Core.Controls;
using TweetDck.Core.Utils;
using TweetDck.Resources;
namespace TweetDck.Updates{
@@ -70,6 +71,12 @@ namespace TweetDck.Updates{
}
}
public bool IsSystemSupported{
get{
return Environment.OSVersion.Version >= new Version("6.1"); // 6.1 NT version = Windows 7
}
}
private readonly UpdateHandler owner;
public Bridge(UpdateHandler owner){
@@ -90,6 +97,10 @@ namespace TweetDck.Updates{
Program.UserConfig.Save();
});
}
public void OpenBrowser(string url){
BrowserUtils.OpenExternalBrowser(url);
}
}
}
}

View File

@@ -1,9 +1,5 @@
del "bin\x86\Release Dick\*.xml"
del "bin\x86\Release Dick\devtools_resources.pak"
del "bin\x86\Release Duck\*.xml"
del "bin\x86\Release Duck\devtools_resources.pak"
del "bin\x86\Release\*.xml"
del "bin\x86\Release\devtools_resources.pak"
del "bin\x86\Release Dick\TweetDick.Browser.exe"
ren "bin\x86\Release Dick\CefSharp.BrowserSubprocess.exe" "TweetDick.Browser.exe"
del "bin\x86\Release Duck\TweetDuck.Browser.exe"
ren "bin\x86\Release Duck\CefSharp.BrowserSubprocess.exe" "TweetDuck.Browser.exe"
del "bin\x86\Release\TweetDuck.Browser.exe"
ren "bin\x86\Release\CefSharp.BrowserSubprocess.exe" "TweetDuck.Browser.exe"