Compare commits

..

333 Commits

Author SHA1 Message Date
Archi
1d96ff8b1f Misc 2023-04-21 11:41:32 +02:00
Archi
1d5bf32ec6 Remove default implementation from interface
Not supported on netf
2023-04-21 11:32:20 +02:00
ArchiBot
cb1648b8c3 Automatic translations update 2023-04-21 02:12:06 +00:00
Archi
1fb74346bd Make IWebInterface work on netf 2023-04-20 22:56:49 +02:00
Archi
b9fd3d0433 Misc 2023-04-20 22:25:38 +02:00
Archi
55b8c8f0d4 Post-PR improvements 2023-04-20 22:24:38 +02:00
fazelukario
97da56d016 Implemented native web GUI support for plugins inside the ASF IPC. Closes #2876 (#2877)
* Implemented native web GUI support for plugins inside the ASF IPC

ref #2876

* calm down netframework

* less `#if`'s

* code optimization

* misc

* Code improvements

* Support nested paths

* Revert "Support nested paths"

This reverts commit 5d7d9ac6ae.

* Support for nested paths (no errors now I guess)

* better path naming

* fixed typos

* Use `HashSet<string>` instead of `List<string>`

* Code improvements

* Code improvements

* Code improvements

* Code improvements

* Code improvements

* Added support for overriding ASF-ui files

* Removed a modified file from pull request

* Added `IWebInterface`

* less `#if`'s

* Code improvements

* Code improvements

* Added license

* Code improvements

* Added default implementation of `IWebInterface`

* Code improvements:
*Use of `OfType<>` instead `Where` and casting.

* Code improvements:
*Null checking

* Removed useless code

* shut up `netf`

* Removed useless null check

* Code improvements:
*Misc: kvp deconstaction

* Added support for absolute path
2023-04-20 22:02:49 +02:00
Archi
69cb5999ea Make 2fafinalized accept code and add 2fafinalizedforce instead 2023-04-20 21:55:19 +02:00
Archi
19ffc1d5d1 Misc
Not needed
2023-04-20 21:32:52 +02:00
Archi
869904e938 Add 2fafinalized command 2023-04-20 21:31:30 +02:00
renovate[bot]
68265993f7 Update ASF-ui digest to d71555d 2023-04-20 08:16:08 +00:00
renovate[bot]
b0a2997bd2 Update ASF-ui digest to 1fcd731 2023-04-18 02:28:26 +00:00
ArchiBot
1e91408044 Automatic translations update 2023-04-18 02:10:44 +00:00
renovate[bot]
136405d9ff Update ASF-ui digest to d243d24 2023-04-17 23:06:31 +00:00
renovate[bot]
deab1a07f6 Update ASF-ui digest to bd10a4a 2023-04-16 03:30:28 +00:00
ArchiBot
7b431033cd Automatic translations update 2023-04-16 02:16:28 +00:00
renovate[bot]
929cedaa2c Update ASF-ui digest to 7015556 2023-04-15 13:04:27 +00:00
Archi
b1bc56d1f2 Add support for AccountLoginDeniedThrottle
Same as RateLimitExceeded
2023-04-15 13:02:10 +02:00
ArchiBot
82a70e282f Automatic translations update 2023-04-15 02:12:33 +00:00
renovate[bot]
269a7cc7a3 Update github/codeql-action action to v2.2.12 2023-04-14 20:57:30 +00:00
renovate[bot]
82dd41d41b Update wiki digest to 15e3ef2 2023-04-14 17:45:15 +00:00
renovate[bot]
9ac2912c38 Update ASF-ui digest to b0bb104 2023-04-14 13:18:58 +00:00
Archi
ff01aff822 Bump 2023-04-14 12:09:13 +02:00
Archi
fc8eb6d1d9 Postpone TradeCheckTimer on new trade received 2023-04-14 11:47:05 +02:00
Archi
45b3183ed6 Misc cleanup 2023-04-14 11:41:51 +02:00
Ryzhehvost
042c2b4e3e Periodically check for outstanding trades. Closes #2871 (#2878)
* add trade check period

* change default value for timer
2023-04-14 11:01:41 +02:00
Archi
15c8c8b714 Add handling of AccessDenied during login procedure 2023-04-14 10:43:33 +02:00
ArchiBot
352d1c6e98 Automatic translations update 2023-04-14 02:10:05 +00:00
renovate[bot]
24d75b72e6 Update actions/checkout action to v3.5.2 2023-04-13 17:46:30 +00:00
renovate[bot]
e8028ae43b Update ASF-ui digest to d1e6d77 2023-04-13 07:06:42 +00:00
renovate[bot]
a65d937ff4 Update actions/checkout action to v3.5.1 (#2880)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-13 09:06:22 +02:00
renovate[bot]
24120f5e70 Update ASF-ui digest to b8dbb95 2023-04-12 08:08:40 +00:00
Archi
a536a411dd Misc 2023-04-10 15:04:08 +02:00
Archi
54c5be7ef0 Bump 2023-04-10 14:56:46 +02:00
Archi
067d478a76 Closes #2873 2023-04-10 14:55:35 +02:00
renovate[bot]
485942d45b Update peter-evans/dockerhub-description action to v3.4.1 2023-04-10 03:32:06 +00:00
ArchiBot
b0eb199aa1 Automatic translations update 2023-04-10 02:09:33 +00:00
Pavel Djundik
19fbdd1bdd Update server url (#2870) 2023-04-09 21:17:39 +02:00
renovate[bot]
9dac86327d Update ASF-ui digest to fce3428 (#2874)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-09 21:17:15 +02:00
renovate[bot]
faf50d0798 Update peter-evans/dockerhub-description action to v3.4.0 2023-04-07 04:34:39 +00:00
ArchiBot
5892454ff4 Automatic translations update 2023-04-07 02:08:56 +00:00
renovate[bot]
1b060549fa Update github/codeql-action action to v2.2.11 2023-04-06 21:18:16 +00:00
renovate[bot]
62bc8cf8d0 Update ASF-ui digest to e599f07 2023-04-06 08:50:54 +00:00
renovate[bot]
54d013a81d Update github/codeql-action action to v2.2.10 2023-04-05 18:30:33 +00:00
ArchiBot
52639d66a6 Automatic translations update 2023-04-05 02:05:15 +00:00
ArchiBot
420b522927 Automatic translations update 2023-04-04 02:13:35 +00:00
Archi
3435d83ea4 Bump 2023-04-03 12:43:39 +02:00
Archi
fc1bdb9b16 Closes #2867 2023-04-03 12:40:36 +02:00
ArchiBot
e443d3f4ab Automatic translations update 2023-04-03 02:09:51 +00:00
Archi
cd40472501 Misc 2023-04-02 23:54:51 +02:00
Archi
4159b379b0 Misc
Thanks @Ryzhehvost
2023-04-02 23:33:07 +02:00
Archi
b1d82da385 Bump 2023-04-02 22:44:42 +02:00
Archi
258ea5df3b Shut up netf 2023-04-02 22:29:46 +02:00
Archi
142d1bdd28 Improve resilency against DuplicateRequest 2023-04-02 22:24:31 +02:00
Archi
b8ba995db0 Handle DuplicateRequest when logging in 2023-04-02 21:38:44 +02:00
Archi
731b5909d1 Closes #2854 2023-04-02 21:26:56 +02:00
renovate[bot]
cd40e5e799 Update ASF-ui digest to bc84d62 2023-04-01 08:56:50 +00:00
renovate[bot]
a9b31a5b41 Update ASF-ui digest to 1107a29 2023-03-31 11:00:29 +00:00
renovate[bot]
9072241d70 Update ASF-ui digest to 5088f79 2023-03-30 03:49:04 +00:00
renovate[bot]
5f7e004956 Update ASF-ui digest to 1768016 2023-03-29 13:23:42 +00:00
renovate[bot]
5ee13455ac Update dependency NLog.Web.AspNetCore to v5.2.3 2023-03-28 21:29:15 +00:00
renovate[bot]
f60c8a220b Update ASF-ui digest to 64a6583 2023-03-28 01:18:16 +00:00
renovate[bot]
cb58c0dc3f Update github/codeql-action action to v2.2.9 2023-03-27 13:55:56 +00:00
renovate[bot]
db77028c6e Update ASF-ui digest to a98f263 2023-03-26 04:39:34 +00:00
ArchiBot
bf907d2d5c Automatic translations update 2023-03-25 02:12:43 +00:00
Archi
fd718b005a Bump 2023-03-24 16:08:37 +01:00
Archi
089cc5beee Closes #2624 2023-03-24 13:56:38 +01:00
Archi
68b22ba64d Add missing support for MobileAuthenticator translations 2023-03-24 13:53:40 +01:00
Archi
dbbfc7344b Closes #2850 2023-03-24 13:51:17 +01:00
renovate[bot]
f1dbf0da6a Update ASF-ui digest to f61f018 2023-03-24 08:35:01 +00:00
renovate[bot]
a99f632bce Update actions/checkout action to v3.5.0 2023-03-24 07:10:29 +00:00
renovate[bot]
e622caf820 Update ASF-ui digest to e51578c 2023-03-24 02:33:03 +00:00
renovate[bot]
3cf43cb837 Update ASF-ui digest to 4844c90 2023-03-23 14:48:38 +00:00
renovate[bot]
a1c241b2cf Update github/codeql-action action to v2.2.8 2023-03-23 06:46:12 +00:00
renovate[bot]
ad0e8fa8b2 Update ASF-ui digest to 8d93ead 2023-03-23 03:51:28 +00:00
ArchiBot
0b5a0875f6 Automatic translations update 2023-03-23 02:13:16 +00:00
ArchiBot
70e996829b Automatic translations update 2023-03-22 02:13:59 +00:00
Łukasz Domeradzki
93f3221378 Misc 2023-03-21 13:03:06 +01:00
ArchiBot
512df5c5e5 Automatic translations update 2023-03-21 02:11:46 +00:00
Archi
d5e5f82e7f Add StartupVideo asset type 2023-03-20 19:53:24 +01:00
ArchiBot
5fa1346f18 Automatic translations update 2023-03-20 02:19:43 +00:00
renovate[bot]
dd62a9ea8e Update ASF-ui digest to 1a81458 2023-03-18 23:09:27 +00:00
renovate[bot]
4796857385 Update ASF-ui digest to 13525c4 2023-03-18 03:09:26 +00:00
Archi
e8679750e1 Bump 2023-03-18 00:33:54 +01:00
Łukasz Domeradzki
dd663f43b9 Closes #2840 (#2843)
* Initial login flow changes

* I hate windows

* Make it compile

* Hehe, you bet

* Another approach

* Misc

* Misc

* Final touches

* Misc

* Okay xpaw

* xPaw update

* Keep set input for reconnection

* Unify login errors

* Add missing registry entry

* Final touches before I lose my sanity
2023-03-17 23:59:46 +01:00
renovate[bot]
25e7e21604 Update ASF-ui digest to 1e372af 2023-03-16 05:43:43 +00:00
renovate[bot]
c4d0c23a0e Update actions/checkout action to v3.4.0 2023-03-15 23:01:55 +00:00
renovate[bot]
2bda115d37 Update github/codeql-action action to v2.2.7 2023-03-15 18:28:53 +00:00
Archi
4d2fdc08c8 Bump 2023-03-15 17:57:06 +01:00
Archi
d2894a8bdc Followup fix 2023-03-15 17:56:24 +01:00
Archi
f685ce598d Bump 2023-03-15 16:07:24 +01:00
Archi
63c206e6c7 Disable revocation check
Likely root cause for https://steamcommunity.com/groups/archiasf/discussions/1/3821906444724042697/
2023-03-15 16:06:53 +01:00
renovate[bot]
b98e23e840 Update ASF-ui digest to e7dad93 2023-03-15 07:05:36 +00:00
renovate[bot]
87cff8f813 Update crowdin/github-action action to v1.7.1 2023-03-14 13:23:03 +00:00
ArchiBot
c337a9b8e1 Automatic translations update 2023-03-14 02:11:37 +00:00
renovate[bot]
c4e75c5b7b Update ASF-ui digest to e6fd69f 2023-03-11 09:06:35 +00:00
ArchiBot
9e59dd69ca Automatic translations update 2023-03-11 02:16:39 +00:00
renovate[bot]
b90707c6d1 Update github/codeql-action action to v2.2.6 2023-03-10 19:05:30 +00:00
renovate[bot]
641dfa4a1d Update docker/setup-buildx-action action to v2.5.0 2023-03-10 11:20:48 +00:00
renovate[bot]
891d6c87c8 Update ASF-ui digest to 3440b7a 2023-03-09 01:25:28 +00:00
renovate[bot]
ccd6720fc1 Update dependency Newtonsoft.Json to v13.0.3 2023-03-08 11:45:46 +00:00
renovate[bot]
7c9bed6441 Update peter-evans/dockerhub-description action to v3.3.0 2023-03-06 07:30:17 +00:00
ArchiBot
4e92de584c Automatic translations update 2023-03-06 02:22:52 +00:00
renovate[bot]
71a70fd274 Update peter-evans/dockerhub-description action to v3.2.0 2023-03-05 04:34:06 +00:00
ArchiBot
554b1fe443 Automatic translations update 2023-03-03 02:53:30 +00:00
ArchiBot
93ee2c38fb Automatic translations update 2023-03-01 02:24:54 +00:00
ArchiBot
8cde60e7d2 Automatic translations update 2023-02-28 02:22:02 +00:00
renovate[bot]
eeef41e67f Update wiki digest to f1dd80f 2023-02-27 18:03:41 +00:00
renovate[bot]
aeba4f2028 Update dependency Markdig.Signed to v0.31.0 2023-02-27 10:07:17 +00:00
renovate[bot]
5794233013 Update ASF-ui digest to 9a59cc9 2023-02-27 10:06:48 +00:00
ArchiBot
95df482938 Automatic translations update 2023-02-27 02:22:18 +00:00
renovate[bot]
a0766ffe41 Update wiki digest to 76c1aa4 2023-02-26 18:15:13 +00:00
Archi
bae511d2cf Bump + misc 2023-02-26 14:11:43 +01:00
Archi
10007e0752 Closes #2824 2023-02-26 13:43:25 +01:00
Łukasz Domeradzki
c89366b0a6 Closes #2827 (#2829) 2023-02-26 10:59:48 +01:00
ArchiBot
402867a025 Automatic translations update 2023-02-26 02:24:02 +00:00
ArchiBot
8223d09524 Automatic translations update 2023-02-25 02:21:51 +00:00
renovate[bot]
2a74778c32 Update github/codeql-action action to v2.2.5 2023-02-24 20:29:28 +00:00
ArchiBot
cb8dad153c Automatic translations update 2023-02-24 02:21:04 +00:00
Archi
f9efaed524 Misc 2023-02-23 17:20:08 +01:00
renovate[bot]
d38b4568eb Update ASF-ui digest to b30b3f5 2023-02-23 04:42:13 +00:00
ArchiBot
afd1c89ca8 Automatic translations update 2023-02-23 02:21:14 +00:00
ArchiBot
259700f899 Automatic translations update 2023-02-22 02:21:44 +00:00
renovate[bot]
fd86ee9823 Update dependency Microsoft.NET.Test.Sdk to v17.5.0 2023-02-21 10:35:08 +00:00
renovate[bot]
207c52e97f Update ASF-ui digest to 8a85633 2023-02-21 02:45:03 +00:00
ArchiBot
1b025481d5 Automatic translations update 2023-02-21 02:22:15 +00:00
ArchiBot
a871d283b0 Automatic translations update 2023-02-20 02:22:26 +00:00
ArchiBot
94f9d580f3 Automatic translations update 2023-02-19 02:22:10 +00:00
renovate[bot]
26193f62a9 Update dependency NLog.Web.AspNetCore to v5.2.2 2023-02-18 08:24:19 +00:00
renovate[bot]
372175b0c0 Update ASF-ui digest to 900dab6 2023-02-18 06:00:56 +00:00
ArchiBot
8322e39f37 Automatic translations update 2023-02-18 02:20:32 +00:00
renovate[bot]
0d4ba1b81d Update ASF-ui digest to 2c9d017 2023-02-17 08:23:08 +00:00
ArchiBot
a63a321072 Automatic translations update 2023-02-17 02:22:54 +00:00
renovate[bot]
a8ce7f2fdd Update ASF-ui digest to 77bbc49 2023-02-16 05:40:51 +00:00
ArchiBot
dfa967535b Automatic translations update 2023-02-16 02:21:45 +00:00
renovate[bot]
f92b77ac2e Update crowdin/github-action action to v1.7.0 2023-02-15 19:37:16 +00:00
renovate[bot]
ddf73e2089 Update JetBrains/qodana-action action to v2022.3.4 2023-02-15 16:10:38 +00:00
ArchiBot
722c79f1ac Automatic translations update 2023-02-15 02:22:15 +00:00
renovate[bot]
67194f6281 Update dependency System.Security.Cryptography.ProtectedData to v7.0.1 2023-02-14 15:24:48 +00:00
renovate[bot]
28289cb673 Update ASF-ui digest to 303ff51 2023-02-14 12:07:46 +00:00
ArchiBot
29d33c7796 Automatic translations update 2023-02-14 02:22:06 +00:00
renovate[bot]
aebb6a26a7 Update ASF-ui digest to 9b128b6 2023-02-13 20:22:52 +00:00
ArchiBot
f357092808 Automatic translations update 2023-02-13 02:22:09 +00:00
renovate[bot]
8cef49f258 Update wiki digest to 56e86e3 2023-02-12 21:01:03 +00:00
Archi
71b39570b3 Misc 2023-02-12 18:49:53 +01:00
Archi
64c5cec113 Misc 2023-02-12 18:48:03 +01:00
ArchiBot
5bdfab5fb2 Automatic translations update 2023-02-12 02:21:50 +00:00
Archi
e1fc57c19c Bump 2023-02-11 16:06:53 +01:00
Archi
f5812fc28a Good job archo 2023-02-11 16:06:23 +01:00
Archi
d7e8710333 Do not announce/match with limited accounts, lockdowns and trade bans, improve ArchiCacheable
We can totally make use of success previously more often
2023-02-11 15:58:15 +01:00
renovate[bot]
a0f521d4f4 Update ASF-ui digest to 4fb4d2d 2023-02-11 06:22:34 +00:00
ArchiBot
f82e79a41b Automatic translations update 2023-02-11 02:20:17 +00:00
renovate[bot]
5b3469cb1b Update github/codeql-action action to v2.2.4 2023-02-10 19:48:51 +00:00
renovate[bot]
dc2b7bc425 Update github/codeql-action action to v2.2.3 2023-02-10 06:47:59 +00:00
ArchiBot
0da63aba2b Automatic translations update 2023-02-10 02:48:29 +00:00
Archi
eee6457a7d Rename 2fasms to 2fafinalize 2023-02-10 00:39:28 +01:00
Łukasz Domeradzki
a12c11d334 Add ArchiSteamFarm.OfficialPlugins.MobileAuthenticator (#2822)
* Initial commit for 2FA plugin

* Shut up netf

* Actually import this authenticator right into ASF, and add safeguards

* Further fixes

* Render device_id in the resulting maFile
2023-02-10 00:37:26 +01:00
Archi
19349cc3c2 Bump 2023-02-09 20:06:46 +01:00
Archi
4b0a0157aa Bump 2023-02-09 17:22:51 +01:00
Archi
e211588915 CD: Publish improvements
Cuts on publishing time and actual work generated
2023-02-09 17:22:31 +01:00
Łukasz Domeradzki
a89cb28255 Add support for win-arm64 (#2821) 2023-02-09 14:08:39 +01:00
renovate[bot]
0b2f694fb0 Update ASF-ui digest to 36d0d00 2023-02-09 03:27:40 +00:00
ArchiBot
7e11e62f92 Automatic translations update 2023-02-09 02:42:36 +00:00
Archi
3236477702 Update qodana link 2023-02-09 03:32:40 +01:00
Archi
8008a04354 Code cleanups and improvements
- Make use of new UnixFileMode, always one native method we need to maintain less
- Add madness support for it, because new feature of course
- Add optional netstandard target and required compatibility for it, so I can test netf-oriented changes easier
2023-02-09 02:25:11 +01:00
Archi
b2c34694ae Misc code improvements 2023-02-08 21:18:20 +01:00
Archi
738a2c3508 Disable failTreshold until false positives are gone
e.g. https://youtrack.jetbrains.com/issue/QD-5167
2023-02-08 21:10:38 +01:00
Archi
06e10fa32a Add initial support for Qodana 2023-02-08 20:57:36 +01:00
Łukasz Domeradzki
d3490b4e92 Add --minimized command-line argument (#2817)
* Add experimental support for --minimized on Windows

* Simplify the code
2023-02-08 16:11:50 +01:00
renovate[bot]
573080e6c0 Update wiki digest to 02f4ac6 2023-02-08 07:03:48 +00:00
renovate[bot]
239cac2f62 Update ASF-ui digest to 07db676 2023-02-07 23:22:53 +00:00
ArchiBot
6db8a7b2b1 Automatic translations update 2023-02-07 02:34:06 +00:00
renovate[bot]
ea6fdafdbf Update docker/setup-buildx-action action to v2.4.1 2023-02-06 14:46:57 +00:00
ArchiBot
e864bd1d78 Automatic translations update 2023-02-06 02:18:32 +00:00
ArchiBot
b41a4ca572 Automatic translations update 2023-02-05 02:22:06 +00:00
Archi
dcdc3d4870 Misc 2023-02-04 20:23:32 +01:00
Archi
dc97558ad5 Misc 2023-02-04 16:02:28 +01:00
renovate[bot]
1cdb597acc Update ASF-ui digest to 56fb974 2023-02-04 05:18:50 +00:00
ArchiBot
1e328f8de8 Automatic translations update 2023-02-04 02:17:59 +00:00
renovate[bot]
bfc50f5861 Update wiki digest to f56cd3d 2023-02-03 13:59:53 +00:00
ArchiBot
04e338ace8 Automatic translations update 2023-02-03 02:22:04 +00:00
Archi
9f272ae490 Misc 2023-02-03 03:00:42 +01:00
Archi
e266b8ad31 Actually, this makes more sense 2023-02-03 02:32:17 +01:00
Archi
a8b28efe43 ASFB HttpClientHandler improvements
We should increase our security by checking against revoked SSL certificates, just in case.

When using proxy, pre-authenticating makes sense since if user provided the credentials, we can be pretty sure they're required and save a roundtrip.
2023-02-03 02:29:55 +01:00
renovate[bot]
6e8672cf84 Update ASF-ui digest to 54d5dc8 2023-02-02 06:11:01 +00:00
ArchiBot
8d7f68381b Automatic translations update 2023-02-02 02:21:18 +00:00
renovate[bot]
d7d67c11f9 Update wiki digest to 829f7e8 2023-02-01 15:58:17 +00:00
renovate[bot]
1f711f03d1 Update ASF-ui digest to 30f0bf0 2023-02-01 07:56:17 +00:00
ArchiBot
67e989b2a5 Automatic translations update 2023-02-01 02:24:04 +00:00
Archi
fd3ebe2819 Bump 2023-01-31 22:21:00 +01:00
Archi
17d9c9bc22 Prefer maximum compression on compressed requests
We have many clients and a single server, pushing additional work at the clients will typically degrade the effective speed with which the data can be transmitted, but will allow our server to handle more requests concurrently due to less bandwidth used, and will positively affect the bandwidth used for both server and the client.
2023-01-31 22:19:41 +01:00
renovate[bot]
d4efe537d9 Update docker/build-push-action action to v4 (#2813)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-31 15:07:31 +01:00
ArchiBot
95005565db Automatic translations update 2023-01-31 02:21:58 +00:00
renovate[bot]
c538eab00e Update docker/build-push-action action to v3.3.1 2023-01-30 21:56:28 +00:00
renovate[bot]
63ccf65ba0 Update docker/setup-buildx-action action to v2.4.0 2023-01-30 13:02:37 +00:00
ArchiBot
dcbd69f7e6 Automatic translations update 2023-01-30 02:18:12 +00:00
Archi
2b0c29d005 Oh right, this too 2023-01-29 23:02:48 +01:00
Archi
4b5a75eebc Satisfy netf, I'm too lazy to add madness support for it now 2023-01-29 23:00:35 +01:00
Archi
be8a441e2e Add ArchiSteamFarm.CustomPlugins.SignInWithSteam 2023-01-29 22:51:25 +01:00
renovate[bot]
aff62da00e Update ASF-ui digest to 22692a1 2023-01-29 05:44:06 +00:00
ArchiBot
f40600bccf Automatic translations update 2023-01-29 02:21:16 +00:00
renovate[bot]
6fc5de4105 Update docker/setup-buildx-action action to v2.3.0 2023-01-28 04:57:51 +00:00
ArchiBot
c7f35670bf Automatic translations update 2023-01-28 02:20:33 +00:00
renovate[bot]
36c9ace28e Update wiki digest to ec5b9ab 2023-01-27 21:30:43 +00:00
renovate[bot]
bab539ece3 Update ASF-ui digest to a3e6e1f 2023-01-27 05:04:18 +00:00
ArchiBot
1542efcda4 Automatic translations update 2023-01-27 02:20:39 +00:00
renovate[bot]
8129f1d707 Update ASF-ui digest to 5784179 2023-01-26 17:46:38 +00:00
renovate[bot]
142e574c5a Update crowdin/github-action action to v1.6.0 2023-01-26 09:47:49 +00:00
ArchiBot
b2871523c1 Automatic translations update 2023-01-26 02:19:40 +00:00
Sebastian Göls
0c125db118 Happy new year! (#2809) 2023-01-25 15:43:12 +01:00
renovate[bot]
dbcfef99be Update ASF-ui digest to 11f5159 2023-01-25 14:29:52 +00:00
ArchiBot
c49008400f Automatic translations update 2023-01-25 02:19:22 +00:00
Archi
ebd8cbf270 Remove no longer needed debugging leftover
Since interactive console is much more convenient to debug with, this no longer serves any purpose
2023-01-24 23:25:39 +01:00
Archi
b323a17fba Bump 2023-01-24 23:21:25 +01:00
Archi
4798b29bff Misc 2023-01-24 23:00:27 +01:00
Łukasz Domeradzki
df4f8d1e62 Improve fairness logic (#2807)
* Improve fairness logic

* Add unit test against abuse

* Further simplify the code

That first pass is not needed anymore, first loop covers it
2023-01-24 22:55:15 +01:00
Archi
00f7d2bfb9 Closes #2787 2023-01-24 22:49:41 +01:00
renovate[bot]
5ab1971018 Update ASF-ui digest to 94ce7b1 2023-01-24 05:32:33 +00:00
ArchiBot
841b80c297 Automatic translations update 2023-01-24 02:18:42 +00:00
Archi
10f2471332 CD: Upload sha512 sums first
So I can !asfapprove faster, lol
2023-01-24 02:27:37 +01:00
Archi
fccb455676 Bump 2023-01-24 01:40:27 +01:00
Archi
c9bc71462e Misc 2023-01-24 01:39:46 +01:00
Archi
e0f9fe3555 Skip empty nickname in self persona state callback 2023-01-24 01:29:55 +01:00
Archi
8bb48d829e STD: Add support for KnownDepotIDs 2023-01-23 12:08:30 +01:00
Archi
4c166102c5 Misc 2023-01-23 11:30:01 +01:00
Archi
a91a4aada6 Fetch main depot key only if we managed to fetch some other ones 2023-01-23 11:25:20 +01:00
renovate[bot]
e05139ea7f Update ASF-ui digest to a3cc476 2023-01-23 04:25:35 +00:00
ArchiBot
6119d33ab8 Automatic translations update 2023-01-23 02:18:51 +00:00
renovate[bot]
5905412d82 Update ASF-ui digest to b2dd529 2023-01-22 04:07:36 +00:00
ArchiBot
7596a89baa Automatic translations update 2023-01-22 02:20:35 +00:00
Archi
7e7fd3bab4 Bump 2023-01-21 23:28:23 +01:00
Archi
8ab6137ab1 Ensure we don't skip announcement if our trade token has changed
We don't care about nickname or avatar hash, even total amount of items is not that important, but trade token is crucial for matching
2023-01-21 23:23:08 +01:00
Archi
a01ea00873 STD: Add 500ms delay between depot key requests 2023-01-21 21:16:01 +01:00
Archi
4cb8244353 Move to announce endpoint v3
By using ordered list for json body, we can further minimize amount of data sent by getting rid of the index.

We still need previous asset ID, as we send only a subset of real data and server is unable to calculate it from the data sent.
2023-01-21 20:32:42 +01:00
renovate[bot]
41fef74e36 Update ASF-ui digest to 80e6bd5 2023-01-21 03:42:51 +00:00
ArchiBot
58376c0a10 Automatic translations update 2023-01-21 02:18:43 +00:00
Archi
628386859b Misc 2023-01-20 14:22:57 +01:00
Archi
1b0fe9cf45 Add desktop entry for generic and generic-netf too 2023-01-20 14:21:03 +01:00
Archi
946e88fb51 Remove unnecessary quotation 2023-01-20 13:56:33 +01:00
Archi
eed29fc330 Add desktop entry for linux 2023-01-20 13:48:31 +01:00
ArchiBot
da4ba2cda7 Automatic translations update 2023-01-20 02:22:00 +00:00
Archi
b9c75e73f0 Do a recovery of single depot tasks 2023-01-19 15:17:47 +01:00
Archi
cca21900a6 Allow STD requests to fail, and continue with other ones 2023-01-19 15:06:06 +01:00
renovate[bot]
a357953d0a Update ASF-ui digest to f813474 2023-01-19 04:37:00 +00:00
ArchiBot
bb58ec75f3 Automatic translations update 2023-01-19 02:36:34 +00:00
Archi
8aad8b6bcf Misc 2023-01-18 23:11:17 +01:00
Archi
1597786668 Bump 2023-01-18 23:01:39 +01:00
Archi
239d523513 Skip announcements during matching 2023-01-18 22:52:25 +01:00
Archi
3165bf62b4 Bump 2023-01-18 14:19:00 +01:00
Archi
bcfeb66ba4 Allow maximum of 10 pending to confirm trade offers at once 2023-01-18 14:16:35 +01:00
renovate[bot]
2e9c1042e1 Update ASF-ui digest to ecf6e1b 2023-01-18 07:22:03 +00:00
ArchiBot
1a26844cd8 Automatic translations update 2023-01-18 02:20:59 +00:00
Archi
7fb32effc1 Bump 2023-01-17 19:44:15 +01:00
Archi
28a3e27a5e Account for failures in a row when sending trade offers
We expect those to be occassional, but getting 5 in a row from 5 different users, that's extremely suspicious
2023-01-17 19:42:29 +01:00
Archi
27639b32d5 Accept all confirmations from ItemsMatcher at once
Previously we accepted those after each trade, because the overhead of loading other inventory was too big to leave those pending. Since we have all possible matches at once now, it makes sense to firstly schedule all trade offers, and then just confirm them all at once, especially since confirmations endpoint is horrific and very often problematic, on top of having 10-seconds rate-limiting.
2023-01-17 19:19:27 +01:00
Archi
5049f82dad Don't stop matching on occassional two factor failure 2023-01-17 19:00:31 +01:00
renovate[bot]
d0a0877a92 Update crowdin/github-action action to v1.5.3 2023-01-17 10:50:00 +00:00
renovate[bot]
70880a9f44 Update ASF-ui digest to 91a1d47 2023-01-17 02:41:35 +00:00
ArchiBot
ece3fb9c55 Automatic translations update 2023-01-17 02:19:39 +00:00
renovate[bot]
27b2061082 Update wiki digest to 2ab9176 2023-01-16 18:24:00 +00:00
ArchiBot
1d5ed1c080 Automatic translations update 2023-01-16 02:20:27 +00:00
Archi
f3593de457 Misc 2023-01-15 22:31:51 +01:00
Archi
8d34e4b798 Bump 2023-01-15 21:51:06 +01:00
Archi
d68b900055 Move http client compression to utilities
We don't really need standalone class, contrary to my first expectation
2023-01-15 21:46:58 +01:00
Archi
164b009a32 Enable response compression also for https in kestrel 2023-01-15 21:37:41 +01:00
Łukasz Domeradzki
ca9cccf5da Add support for request compression (#2805)
* Add support for brotli request compression

* Refactor and add support for netf

* Use fastest compression
2023-01-15 21:26:03 +01:00
renovate[bot]
508130c0bc Update ASF-ui digest to 09afe10 2023-01-15 11:44:34 +00:00
renovate[bot]
c2781fe9d2 Update wiki digest to 3507b52 2023-01-15 05:21:40 +00:00
renovate[bot]
bc8a08b9cc Update ASF-ui digest to 854f95f 2023-01-15 03:09:08 +00:00
ArchiBot
96277fb7a3 Automatic translations update 2023-01-15 02:20:45 +00:00
Archi
fc93f86060 Improve preferences of matching
We should try to match smallest bots first, but since assets are deduplicated exclusively for us, we should use total inventory count instead
2023-01-15 01:04:15 +01:00
Archi
7466db57cf Bump 2023-01-15 00:25:15 +01:00
Archi
e5ff2e9f02 Include TotalInventoryCount for the backend 2023-01-15 00:16:53 +01:00
Archi
88cec38df4 Decrease overhead for calculating tradable sets for announcement
We don't care about classIDs there, only amounts
2023-01-14 23:57:45 +01:00
Archi
d506cf8ed2 Bump 2023-01-14 23:48:57 +01:00
Archi
8e7d05ce5c Skip untradable items for MatchEverything bots 2023-01-14 23:41:25 +01:00
Archi
f9ca0bdb8b Bump 2023-01-14 23:22:42 +01:00
Archi
eada4356f7 Remove MinItemsCount requirement 2023-01-14 23:08:13 +01:00
Archi
ca06d03475 Relax listing requirement
We no longer require 100 tradable items, but rather, 100 total items. We can also further optimize the payload by removing assets where we have no tradable items at all.
2023-01-14 22:24:21 +01:00
Archi
62fd4aee12 Bump 2023-01-14 15:10:38 +01:00
Archi
e6e82e19bd Cut excessive data from announcement
Now that we don't need to transmit whole inventory to the backend anymore, we can cut it to matchable types only
2023-01-14 15:08:28 +01:00
renovate[bot]
289e539c38 Update docker/build-push-action action to v3.3.0 2023-01-14 09:28:45 +00:00
ArchiBot
91f4e47ff6 Automatic translations update 2023-01-14 02:16:04 +00:00
Archi
18cd12040f Bump 2023-01-13 17:17:06 +01:00
Archi
55f7235a32 Misc 2023-01-13 17:16:15 +01:00
Archi
45d434e64e Misc 2023-01-13 10:43:45 +01:00
Łukasz Domeradzki
0261076021 Ignore QUIC exceptions (#2800)
* Ignore QUIC exceptions

See https://github.com/dotnet/runtime/issues/80111

* Update madness

* No i jaki jest twój problem ja się pytam
2023-01-13 10:40:37 +01:00
renovate[bot]
39650c6a4d Update ASF-ui digest to 80b91db 2023-01-13 05:07:57 +00:00
ArchiBot
a29c73e38f Automatic translations update 2023-01-13 02:40:35 +00:00
renovate[bot]
adfaf1e2f4 Update dependency JustArchiNET.Madness to v3.10.0 2023-01-12 17:52:10 +00:00
renovate[bot]
656e98944c Update ASF-ui digest to bdd72e1 2023-01-12 13:33:00 +00:00
Archi
84be0f8077 Misc
We can save some excessive memory I guess
2023-01-12 11:47:45 +01:00
Archi
8cc705feff Skip pointless announcements if possible 2023-01-12 11:42:04 +01:00
renovate[bot]
e248948002 Update swashbuckle-aspnetcore monorepo to v6.5.0 2023-01-12 02:36:40 +00:00
ArchiBot
a3ba0b680d Automatic translations update 2023-01-12 02:35:26 +00:00
Archi
ac5cd5c08b Bump 2023-01-11 20:22:37 +01:00
Archi
ca67285f34 No users to match against is expected 2023-01-11 20:15:19 +01:00
Archi
097ac05ceb Remove assetID from inventories request
Backend doesn't need to know that
2023-01-11 19:16:38 +01:00
Archi
4895a95794 Decrease size of the request
We reached a point where it actually matters whether we say "realAppID" or just "r", since we're doing this sometimes even 600k times, multiplied by 9 properties that we have
2023-01-11 18:40:46 +01:00
Archi
3cadcd16b4 Help ArchiNet calculating previous asset IDs if possible 2023-01-11 18:34:31 +01:00
renovate[bot]
830fc982f7 Update wiki digest to 79da627 2023-01-11 10:47:14 +00:00
ArchiBot
340ef6482b Automatic translations update 2023-01-11 02:36:39 +00:00
renovate[bot]
ae63fe86ec Update ASF-ui digest to d4efcd3 2023-01-10 03:21:02 +00:00
ArchiBot
e4ece7da95 Automatic translations update 2023-01-10 02:40:05 +00:00
renovate[bot]
d9bbf117bc Update wiki digest to 8d8cf78 2023-01-09 20:10:31 +00:00
ArchiBot
bcdfaf36c9 Automatic translations update 2023-01-09 02:18:51 +00:00
ArchiBot
76ff45a7a3 Automatic translations update 2023-01-08 02:21:17 +00:00
renovate[bot]
447125761d Update wiki digest to 1eafa5f 2023-01-07 15:41:40 +00:00
renovate[bot]
94fbcc6a21 Update actions/upload-artifact action to v3.1.2 2023-01-07 03:15:50 +00:00
ArchiBot
743c1c76f6 Automatic translations update 2023-01-07 02:18:15 +00:00
renovate[bot]
7a2972569a Update ASF-ui digest to 2444752 2023-01-06 21:19:06 +00:00
Archi
2b15b9f84e Optimize filtering of no-dupes
Slightly decreases CPU spent, since we calculate sets to remove only once rather than on each entry
2023-01-06 20:58:35 +01:00
renovate[bot]
4b300f27a8 Update actions/download-artifact action to v3.0.2 2023-01-06 08:08:14 +00:00
renovate[bot]
4c315685e7 Update wiki digest to d2d08f2 2023-01-06 05:40:06 +00:00
renovate[bot]
936994704c Update ASF-ui digest to 1172a8d 2023-01-06 02:44:14 +00:00
ArchiBot
873a109f84 Automatic translations update 2023-01-06 02:21:02 +00:00
renovate[bot]
76d7528fe9 Update actions/setup-node action to v3.6.0 2023-01-05 19:47:53 +00:00
renovate[bot]
725ecf7ce8 Update actions/checkout action to v3.3.0 2023-01-05 16:47:18 +00:00
Archi
7289c92273 Bump 2023-01-05 14:30:27 +01:00
Archi
dea715ff1e Decrease announcement time, set listener for finished trade offers 2023-01-05 14:30:08 +01:00
renovate[bot]
8a497fe4d3 Update ASF-ui digest to ba45ee9 2023-01-05 04:38:54 +00:00
ArchiBot
c8e7fae49e Automatic translations update 2023-01-05 02:20:07 +00:00
renovate[bot]
55f8548304 Update wiki digest to 23985bb 2023-01-04 22:34:10 +00:00
renovate[bot]
a1582555ed Update ASF-ui digest to 1bc1482 2023-01-04 09:33:12 +00:00
ArchiBot
70116cb88a Automatic translations update 2023-01-04 02:19:13 +00:00
ArchiBot
e7845422dc Automatic translations update 2023-01-03 02:16:42 +00:00
renovate[bot]
5408c751d3 Update wiki digest to f6b972e 2023-01-02 21:11:52 +00:00
ArchiBot
e83fb7d394 Automatic translations update 2023-01-02 02:17:27 +00:00
Archi
c4b1428be1 Closes #2790 2022-12-31 23:12:52 +01:00
renovate[bot]
526f5f5d10 Update ASF-ui digest to 25d46d7 2022-12-31 11:32:19 +00:00
renovate[bot]
99ee0575b0 Update ASF-ui digest to 5940bd4 2022-12-31 02:44:12 +00:00
ArchiBot
36a140faf2 Automatic translations update 2022-12-31 02:15:37 +00:00
Archi
a5da2c8daf Bump 2022-12-30 17:22:49 +01:00
356 changed files with 7032 additions and 2001 deletions

11
.github/crowdin.yml vendored
View File

@@ -23,6 +23,17 @@
".zh-TW.resx": ".zh-Hant.resx"
}
},
{
"source": "/ArchiSteamFarm.OfficialPlugins.MobileAuthenticator/Localization/Strings.resx",
"translation": "/ArchiSteamFarm.OfficialPlugins.MobileAuthenticator/Localization/Strings.%locale%.resx",
"translation_replace": {
".lol-US.resx": ".qps-Ploc.resx",
".sr-CS.resx": ".sr-Latn.resx",
".zh-CN.resx": ".zh-Hans.resx",
".zh-HK.resx": ".zh-Hant-HK.resx",
".zh-TW.resx": ".zh-Hant.resx"
}
},
{
"source": "/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization/Strings.resx",
"translation": "/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization/Strings.%locale%.resx",

View File

@@ -19,7 +19,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.5.2
with:
submodules: recursive
@@ -39,7 +39,7 @@ jobs:
- name: Upload latest strings for translation on Crowdin
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && matrix.configuration == 'Release' && startsWith(matrix.os, 'ubuntu-') }}
uses: crowdin/github-action@1.5.2
uses: crowdin/github-action@v1.7.1
with:
crowdin_branch_name: main
config: '.github/crowdin.yml'

25
.github/workflows/code-quality.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: ASF-code-quality
on: [push, pull_request]
env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3.5.2
- name: Run Qodana scan
uses: JetBrains/qodana-action@v2022.3.4
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
- name: Report Qodana results to GitHub
uses: github/codeql-action/upload-sarif@v2.2.12
with:
sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json

View File

@@ -17,15 +17,15 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.5.2
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2.2.1
uses: docker/setup-buildx-action@v2.5.0
- name: Build ${{ matrix.configuration }} Docker image from ${{ matrix.file }}
uses: docker/build-push-action@v3.2.0
uses: docker/build-push-action@v4.0.0
with:
context: .
file: ${{ matrix.file }}

View File

@@ -15,12 +15,12 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.5.2
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2.2.1
uses: docker/setup-buildx-action@v2.5.0
- name: Login to ghcr.io
uses: docker/login-action@v2.1.0
@@ -55,7 +55,7 @@ jobs:
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Build and publish Docker image from Dockerfile.Service
uses: docker/build-push-action@v3.2.0
uses: docker/build-push-action@v4.0.0
with:
context: .
file: Dockerfile.Service

View File

@@ -16,12 +16,12 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.5.2
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2.2.1
uses: docker/setup-buildx-action@v2.5.0
- name: Login to ghcr.io
uses: docker/login-action@v2.1.0
@@ -55,7 +55,7 @@ jobs:
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Build and publish Docker image from Dockerfile
uses: docker/build-push-action@v3.2.0
uses: docker/build-push-action@v4.0.0
with:
context: .
platforms: ${{ env.PLATFORMS }}
@@ -70,7 +70,7 @@ jobs:
push: true
- name: Update DockerHub repository description
uses: peter-evans/dockerhub-description@v3.1.2
uses: peter-evans/dockerhub-description@v3.4.1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}

View File

@@ -16,12 +16,12 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.5.2
with:
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2.2.1
uses: docker/setup-buildx-action@v2.5.0
- name: Login to ghcr.io
uses: docker/login-action@v2.1.0
@@ -56,7 +56,7 @@ jobs:
echo "DH_REPOSITORY=$(echo ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- name: Build and publish Docker image from Dockerfile
uses: docker/build-push-action@v3.2.0
uses: docker/build-push-action@v4.0.0
with:
context: .
platforms: ${{ env.PLATFORMS }}

View File

@@ -3,42 +3,25 @@ name: ASF-publish
on: [push, pull_request]
env:
ASF_PRIVATE_SNK: ${{ secrets.ASF_PRIVATE_SNK }}
CONFIGURATION: Release
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
DOTNET_SDK_VERSION: 7.0.x
NET_CORE_VERSION: net7.0
NET_FRAMEWORK_VERSION: net481
NODE_JS_VERSION: 'lts/*'
PLUGINS: ArchiSteamFarm.OfficialPlugins.ItemsMatcher ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
STEAM_TOKEN_DUMPER_TOKEN: ${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
PLUGINS: ArchiSteamFarm.OfficialPlugins.ItemsMatcher ArchiSteamFarm.OfficialPlugins.MobileAuthenticator ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
jobs:
publish:
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
publish-asf-ui:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.5.2
with:
submodules: recursive
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.0.3
with:
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
- name: Verify .NET Core
run: dotnet --info
- name: Setup Node.js with npm
uses: actions/setup-node@v3.5.1
uses: actions/setup-node@v3.6.0
with:
check-latest: true
node-version: ${{ env.NODE_JS_VERSION }}
@@ -55,8 +38,66 @@ jobs:
- name: Publish ASF-ui
run: npm run-script deploy --no-progress --prefix ASF-ui
- name: Upload ASF-ui
uses: actions/upload-artifact@v3.1.2
with:
name: ASF-ui
path: ASF-ui/dist
publish-asf:
needs: publish-asf-ui
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
variant: generic
- os: windows-latest
variant: generic-netf
- os: ubuntu-latest
variant: linux-arm
- os: ubuntu-latest
variant: linux-arm64
- os: ubuntu-latest
variant: linux-x64
- os: macos-latest
variant: osx-arm64
- os: macos-latest
variant: osx-x64
- os: windows-latest
variant: win-arm64
- os: windows-latest
variant: win-x64
runs-on: ${{ matrix.os }}
env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
steps:
- name: Checkout code
uses: actions/checkout@v3.5.2
- name: Setup .NET Core
uses: actions/setup-dotnet@v3.0.3
with:
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
- name: Verify .NET Core
run: dotnet --info
- name: Download previously built ASF-ui
uses: actions/download-artifact@v3.0.2
with:
name: ASF-ui
path: ASF-ui/dist
- name: Prepare private key for signing on Unix
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
env:
ASF_PRIVATE_SNK: ${{ secrets.ASF_PRIVATE_SNK }}
shell: sh
run: |
set -eu
@@ -67,6 +108,8 @@ jobs:
- name: Prepare private key for signing on Windows
if: startsWith(matrix.os, 'windows-')
env:
ASF_PRIVATE_SNK: ${{ secrets.ASF_PRIVATE_SNK }}
shell: pwsh
run: |
Set-StrictMode -Version Latest
@@ -85,15 +128,19 @@ jobs:
- name: Prepare for publishing on Unix
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
env:
TARGET_FRAMEWORK: ${{ (endsWith(matrix.variant, '-netf') && env.NET_FRAMEWORK_VERSION) || env.NET_CORE_VERSION }}
shell: bash
run: |
set -euo pipefail
dotnet restore
dotnet build ArchiSteamFarm -c "$CONFIGURATION" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
dotnet build ArchiSteamFarm -c "$CONFIGURATION" -f "$TARGET_FRAMEWORK" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
- name: Prepare for publishing on Windows
if: startsWith(matrix.os, 'windows-')
env:
TARGET_FRAMEWORK: ${{ (endsWith(matrix.variant, '-netf') && env.NET_FRAMEWORK_VERSION) || env.NET_CORE_VERSION }}
shell: pwsh
run: |
Set-StrictMode -Version Latest
@@ -101,10 +148,12 @@ jobs:
$ProgressPreference = 'SilentlyContinue'
dotnet restore
dotnet build ArchiSteamFarm -c "$env:CONFIGURATION" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
dotnet build ArchiSteamFarm -c "$env:CONFIGURATION" -f "$env:TARGET_FRAMEWORK" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
- name: Prepare ArchiSteamFarm.OfficialPlugins.SteamTokenDumper on Unix
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
env:
STEAM_TOKEN_DUMPER_TOKEN: ${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
shell: sh
run: |
set -eu
@@ -116,6 +165,8 @@ jobs:
- name: Prepare ArchiSteamFarm.OfficialPlugins.SteamTokenDumper on Windows
if: startsWith(matrix.os, 'windows-')
env:
STEAM_TOKEN_DUMPER_TOKEN: ${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
shell: pwsh
run: |
Set-StrictMode -Version Latest
@@ -129,21 +180,22 @@ jobs:
- name: Publish official plugins on Unix
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
env:
MAX_JOBS: 3
MAX_JOBS: 4
TARGET_FRAMEWORK: ${{ (endsWith(matrix.variant, '-netf') && env.NET_FRAMEWORK_VERSION) || env.NET_CORE_VERSION }}
shell: bash
run: |
set -euo pipefail
publish() {
dotnet publish "$1" -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/${1}/${NET_CORE_VERSION}" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
dotnet publish "$1" -c "$CONFIGURATION" -f "$TARGET_FRAMEWORK" -o "out/${1}/${TARGET_FRAMEWORK}" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
}
for plugin in $PLUGINS; do
publish "$plugin" &
while [ "$(jobs -p | wc -l)" -ge "$MAX_JOBS" ]; do
sleep 1
done
publish "$plugin" &
done
wait
@@ -151,7 +203,8 @@ jobs:
- name: Publish official plugins on Windows
if: startsWith(matrix.os, 'windows-')
env:
MAX_JOBS: 2
MAX_JOBS: 4
TARGET_FRAMEWORK: ${{ (endsWith(matrix.variant, '-netf') && env.NET_FRAMEWORK_VERSION) || env.NET_CORE_VERSION }}
shell: pwsh
run: |
Set-StrictMode -Version Latest
@@ -159,7 +212,7 @@ jobs:
$ProgressPreference = 'SilentlyContinue'
$PublishBlock = {
param($plugin, $framework)
param($plugin)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
@@ -167,7 +220,7 @@ jobs:
Set-Location "$env:GITHUB_WORKSPACE"
dotnet publish "$plugin" -c "$env:CONFIGURATION" -f "$framework" -o "out\$plugin\$framework" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
dotnet publish "$plugin" -c "$env:CONFIGURATION" -f "$env:TARGET_FRAMEWORK" -o "out\$plugin\$env:TARGET_FRAMEWORK" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
if ($LastExitCode -ne 0) {
throw "Last command failed."
@@ -175,215 +228,6 @@ jobs:
}
foreach ($plugin in $env:PLUGINS.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) {
foreach ($framework in "$env:NET_CORE_VERSION","$env:NET_FRAMEWORK_VERSION") {
Start-Job -Name "$plugin $framework" $PublishBlock -ArgumentList "$plugin","$framework"
# Limit active jobs in parallel to help with memory usage
$jobs = $(Get-Job -State Running)
while (@($jobs).Count -ge $env:MAX_JOBS) {
Wait-Job -Job $jobs -Any | Out-Null
$jobs = $(Get-Job -State Running)
}
}
}
Get-Job | Receive-Job -Wait
- name: Publish ArchiSteamFarm on Unix
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
env:
MAX_JOBS: 3
VARIANTS: generic linux-arm linux-arm64 linux-x64 osx-arm64 osx-x64 win-x64 # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs!
shell: bash
run: |
set -euo pipefail
publish() {
if [ "$1" = 'generic' ]; then
variantArgs="-p:TargetLatestRuntimePatch=false -p:UseAppHost=false"
else
variantArgs="-p:PublishSingleFile=true -p:PublishTrimmed=true -r $1 --self-contained"
fi
dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/${1}" "-p:ASFVariant=$1" -p:ContinuousIntegrationBuild=true --no-restore --nologo $variantArgs
# If we're including official plugins for this framework, copy them to output directory
for plugin in $PLUGINS; do
if [ -d "out/${plugin}/${NET_CORE_VERSION}" ]; then
mkdir -p "out/${1}/plugins/${plugin}"
cp -pR "out/${plugin}/${NET_CORE_VERSION}/"* "out/${1}/plugins/${plugin}"
fi
done
# Include .ico file for all platforms, since only Windows script can bundle it inside the exe
cp "resources/ASF.ico" "out/${1}/ArchiSteamFarm.ico"
# By default use fastest compression
seven_zip_args="-mx=1"
zip_args="-1"
# Include extra logic for builds marked for release
case "$GITHUB_REF" in
"refs/tags/"*)
# Tweak compression args for release publishing
seven_zip_args="-mx=9 -mfb=258 -mpass=15"
zip_args="-9"
# Update link in Changelog.html accordingly
if [ -f "out/${1}/Changelog.html" ]; then
tag="$(echo "$GITHUB_REF" | cut -c 11-)"
sed "s/ArchiSteamFarm\/commits\/main/ArchiSteamFarm\/releases\/tag\/${tag}/g" "out/${1}/Changelog.html" > "out/${1}/Changelog.html.new"
mv "out/${1}/Changelog.html.new" "out/${1}/Changelog.html"
fi
;;
esac
# Create the final zip file
case "$(uname -s)" in
"Darwin")
# We prefer to use zip on macOS as 7z implementation on that OS doesn't handle file permissions (chmod +x)
if command -v zip >/dev/null; then
(
cd "${GITHUB_WORKSPACE}/out/${1}"
zip -q -r $zip_args "../ASF-${1}.zip" .
)
elif command -v 7z >/dev/null; then
7z a -bd -slp -tzip -mm=Deflate $seven_zip_args "out/ASF-${1}.zip" "${GITHUB_WORKSPACE}/out/${1}/*"
else
echo "ERROR: No supported zip tool!"
return 1
fi
;;
*)
if command -v 7z >/dev/null; then
7z a -bd -slp -tzip -mm=Deflate $seven_zip_args "out/ASF-${1}.zip" "${GITHUB_WORKSPACE}/out/${1}/*"
elif command -v zip >/dev/null; then
(
cd "${GITHUB_WORKSPACE}/out/${1}"
zip -q -r $zip_args "../ASF-${1}.zip" .
)
else
echo "ERROR: No supported zip tool!"
return 1
fi
;;
esac
}
for variant in $VARIANTS; do
publish "$variant" &
while [ "$(jobs -p | wc -l)" -ge "$MAX_JOBS" ]; do
sleep 1
done
done
wait
- name: Publish ArchiSteamFarm on Windows
if: startsWith(matrix.os, 'windows-')
env:
MAX_JOBS: 2
VARIANTS: generic generic-netf linux-arm linux-arm64 linux-x64 osx-arm64 osx-x64 win-x64 # NOTE: When modifying variants, don't forget to update ASF_VARIANT definitions in SharedInfo.cs!
shell: pwsh
run: |
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'
$PublishBlock = {
param($variant)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'
Set-Location "$env:GITHUB_WORKSPACE"
if ($variant -like '*-netf') {
$targetFramework = $env:NET_FRAMEWORK_VERSION
} else {
$targetFramework = $env:NET_CORE_VERSION
}
if ($variant -like 'generic*') {
$variantArgs = '-p:TargetLatestRuntimePatch=false', '-p:UseAppHost=false'
} else {
$variantArgs = '-p:PublishSingleFile=true', '-p:PublishTrimmed=true', '-r', "$variant", '--self-contained'
}
dotnet publish ArchiSteamFarm -c "$env:CONFIGURATION" -f "$targetFramework" -o "out\$variant" "-p:ASFVariant=$variant" -p:ContinuousIntegrationBuild=true --no-restore --nologo $variantArgs
if ($LastExitCode -ne 0) {
throw "Last command failed."
}
# If we're including official plugins for this framework, copy them to output directory
foreach ($plugin in $env:PLUGINS.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) {
if (Test-Path "out\$plugin\$targetFramework" -PathType Container) {
if (!(Test-Path "out\$variant\plugins\$plugin" -PathType Container)) {
New-Item -ItemType Directory -Path "out\$variant\plugins\$plugin" > $null
}
Copy-Item "out\$plugin\$targetFramework\*" "out\$variant\plugins\$plugin" -Recurse
}
}
# Icon is available only in .NET Framework and .NET Core Windows build, we'll bundle the .ico file for other flavours
if (($targetFramework -eq "$env:NET_CORE_VERSION") -and !(Test-Path "out\$variant\ArchiSteamFarm.exe" -PathType Leaf)) {
Copy-Item 'resources\ASF.ico' "out\$variant\ArchiSteamFarm.ico"
}
# By default use fastest compression
$compressionArgs = '-mx=1'
# Include extra logic for builds marked for release
if ($env:GITHUB_REF -like 'refs/tags/*') {
# Tweak compression args for release publishing
$compressionArgs = '-mx=9', '-mfb=258', '-mpass=15'
# Update link in Changelog.html accordingly
if (Test-Path "out\$variant\Changelog.html" -PathType Leaf) {
$tag = $env:GITHUB_REF.Substring(10)
(Get-Content "out\$variant\Changelog.html").Replace('ArchiSteamFarm/commits/main', "ArchiSteamFarm/releases/tag/$tag") | Set-Content "out\$variant\Changelog.html"
}
}
# Create the final zip file
7z a -bd -slp -tzip -mm=Deflate $compressionArgs "out\ASF-$variant.zip" "$env:GITHUB_WORKSPACE\out\$variant\*"
if ($LastExitCode -ne 0) {
throw "Last command failed."
}
# We can aid non-windows users by adding chmod +x flag to appropriate executables directly in the zip file
# This is ALMOST a hack, but works reliably enough
if (Test-Path "tools\zip_exec\zip_exec.exe" -PathType Leaf) {
$executableFiles = @()
if ($variant -like 'generic*') {
$executableFiles += 'ArchiSteamFarm.sh', 'ArchiSteamFarm-Service.sh'
} elseif (($variant -like 'linux*') -or ($variant -like 'osx*')) {
$executableFiles += 'ArchiSteamFarm', 'ArchiSteamFarm-Service.sh'
}
foreach ($executableFile in $executableFiles) {
tools\zip_exec\zip_exec.exe "out\ASF-$variant.zip" "$executableFile"
if ($LastExitCode -ne 0) {
throw "Last command failed."
}
}
}
}
foreach ($variant in $env:VARIANTS.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) {
Start-Job -Name "$variant" $PublishBlock -ArgumentList "$variant"
# Limit active jobs in parallel to help with memory usage
$jobs = $(Get-Job -State Running)
@@ -392,112 +236,239 @@ jobs:
$jobs = $(Get-Job -State Running)
}
Start-Job -Name "$plugin" $PublishBlock -ArgumentList "$plugin"
}
Get-Job | Receive-Job -Wait
- name: Upload ASF-generic
uses: actions/upload-artifact@v3.1.1
with:
name: ${{ matrix.os }}_ASF-generic
path: out/ASF-generic.zip
- name: Publish ASF-${{ matrix.variant }} on Unix
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
env:
TARGET_FRAMEWORK: ${{ (endsWith(matrix.variant, '-netf') && env.NET_FRAMEWORK_VERSION) || env.NET_CORE_VERSION }}
VARIANT: ${{ matrix.variant }}
shell: bash
run: |
set -euo pipefail
- name: Upload ASF-generic-netf
if [ "$VARIANT" = 'generic' ]; then
variantArgs="-p:TargetLatestRuntimePatch=false -p:UseAppHost=false"
else
variantArgs="-p:PublishSingleFile=true -p:PublishTrimmed=true -r $VARIANT --self-contained"
fi
dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$TARGET_FRAMEWORK" -o "out/${VARIANT}" "-p:ASFVariant=${VARIANT}" -p:ContinuousIntegrationBuild=true --no-restore --nologo $variantArgs
# If we're including official plugins for this framework, copy them to output directory
for plugin in $PLUGINS; do
if [ -d "out/${plugin}/${TARGET_FRAMEWORK}" ]; then
mkdir -p "out/${VARIANT}/plugins/${plugin}"
cp -pR "out/${plugin}/${TARGET_FRAMEWORK}/"* "out/${VARIANT}/plugins/${plugin}"
fi
done
# Include .ico file for all platforms, since only Windows script can bundle it inside the exe
cp "resources/ASF.ico" "out/${VARIANT}/ArchiSteamFarm.ico"
# By default use fastest compression
seven_zip_args="-mx=1"
zip_args="-1"
# Include extra logic for builds marked for release
case "$GITHUB_REF" in
"refs/tags/"*)
# Tweak compression args for release publishing
seven_zip_args="-mx=9 -mfb=258 -mpass=15"
zip_args="-9"
# Update link in Changelog.html accordingly
if [ -f "out/${VARIANT}/Changelog.html" ]; then
tag="$(echo "$GITHUB_REF" | cut -c 11-)"
sed "s/ArchiSteamFarm\/commits\/main/ArchiSteamFarm\/releases\/tag\/${tag}/g" "out/${VARIANT}/Changelog.html" > "out/${VARIANT}/Changelog.html.new"
mv "out/${VARIANT}/Changelog.html.new" "out/${VARIANT}/Changelog.html"
fi
;;
esac
# Create the final zip file
case "$(uname -s)" in
"Darwin")
# We prefer to use zip on macOS as 7z implementation on that OS doesn't handle file permissions (chmod +x)
if command -v zip >/dev/null; then
(
cd "${GITHUB_WORKSPACE}/out/${VARIANT}"
zip -q -r $zip_args "../ASF-${VARIANT}.zip" .
)
elif command -v 7z >/dev/null; then
7z a -bd -slp -tzip -mm=Deflate $seven_zip_args "out/ASF-${VARIANT}.zip" "${GITHUB_WORKSPACE}/out/${VARIANT}/*"
else
echo "ERROR: No supported zip tool!"
return 1
fi
;;
*)
if command -v 7z >/dev/null; then
7z a -bd -slp -tzip -mm=Deflate $seven_zip_args "out/ASF-${VARIANT}.zip" "${GITHUB_WORKSPACE}/out/${VARIANT}/*"
elif command -v zip >/dev/null; then
(
cd "${GITHUB_WORKSPACE}/out/${VARIANT}"
zip -q -r $zip_args "../ASF-${VARIANT}.zip" .
)
else
echo "ERROR: No supported zip tool!"
return 1
fi
;;
esac
- name: Publish ASF-${{ matrix.variant }} on Windows
if: startsWith(matrix.os, 'windows-')
uses: actions/upload-artifact@v3.1.1
with:
name: ${{ matrix.os }}_ASF-generic-netf
path: out/ASF-generic-netf.zip
env:
TARGET_FRAMEWORK: ${{ (endsWith(matrix.variant, '-netf') && env.NET_FRAMEWORK_VERSION) || env.NET_CORE_VERSION }}
VARIANT: ${{ matrix.variant }}
shell: pwsh
run: |
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'
- name: Upload ASF-linux-arm
uses: actions/upload-artifact@v3.1.1
with:
name: ${{ matrix.os }}_ASF-linux-arm
path: out/ASF-linux-arm.zip
if ($env:VARIANT -like 'generic*') {
$variantArgs = '-p:TargetLatestRuntimePatch=false', '-p:UseAppHost=false'
} else {
$variantArgs = '-p:PublishSingleFile=true', '-p:PublishTrimmed=true', '-r', "$env:VARIANT", '--self-contained'
}
- name: Upload ASF-linux-arm64
uses: actions/upload-artifact@v3.1.1
with:
name: ${{ matrix.os }}_ASF-linux-arm64
path: out/ASF-linux-arm64.zip
dotnet publish ArchiSteamFarm -c "$env:CONFIGURATION" -f "$env:TARGET_FRAMEWORK" -o "out\$env:VARIANT" "-p:ASFVariant=$env:VARIANT" -p:ContinuousIntegrationBuild=true --no-restore --nologo $variantArgs
- name: Upload ASF-linux-x64
uses: actions/upload-artifact@v3.1.1
with:
name: ${{ matrix.os }}_ASF-linux-x64
path: out/ASF-linux-x64.zip
if ($LastExitCode -ne 0) {
throw "Last command failed."
}
- name: Upload ASF-osx-arm64
uses: actions/upload-artifact@v3.1.1
with:
name: ${{ matrix.os }}_ASF-osx-arm64
path: out/ASF-osx-arm64.zip
# If we're including official plugins for this framework, copy them to output directory
foreach ($plugin in $env:PLUGINS.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) {
if (Test-Path "out\$plugin\$env:TARGET_FRAMEWORK" -PathType Container) {
if (!(Test-Path "out\$env:VARIANT\plugins\$plugin" -PathType Container)) {
New-Item -ItemType Directory -Path "out\$env:VARIANT\plugins\$plugin" > $null
}
- name: Upload ASF-osx-x64
uses: actions/upload-artifact@v3.1.1
with:
name: ${{ matrix.os }}_ASF-osx-x64
path: out/ASF-osx-x64.zip
Copy-Item "out\$plugin\$env:TARGET_FRAMEWORK\*" "out\$env:VARIANT\plugins\$plugin" -Recurse
}
}
- name: Upload ASF-win-x64
uses: actions/upload-artifact@v3.1.1
# Icon is available only in .exe Windows builds, we'll bundle the .ico file for other flavours
if (!(Test-Path "out\$env:VARIANT\ArchiSteamFarm.exe" -PathType Leaf)) {
Copy-Item 'resources\ASF.ico' "out\$env:VARIANT\ArchiSteamFarm.ico"
}
# By default use fastest compression
$compressionArgs = '-mx=1'
# Include extra logic for builds marked for release
if ($env:GITHUB_REF -like 'refs/tags/*') {
# Tweak compression args for release publishing
$compressionArgs = '-mx=9', '-mfb=258', '-mpass=15'
# Update link in Changelog.html accordingly
if (Test-Path "out\$env:VARIANT\Changelog.html" -PathType Leaf) {
$tag = $env:GITHUB_REF.Substring(10)
(Get-Content "out\$env:VARIANT\Changelog.html").Replace('ArchiSteamFarm/commits/main', "ArchiSteamFarm/releases/tag/$tag") | Set-Content "out\$env:VARIANT\Changelog.html"
}
}
# Create the final zip file
7z a -bd -slp -tzip -mm=Deflate $compressionArgs "out\ASF-$env:VARIANT.zip" "$env:GITHUB_WORKSPACE\out\$env:VARIANT\*"
if ($LastExitCode -ne 0) {
throw "Last command failed."
}
# We can aid non-windows users by adding chmod +x flag to appropriate executables directly in the zip file
# This is ALMOST a hack, but works reliably enough
if (Test-Path "tools\zip_exec\zip_exec.exe" -PathType Leaf) {
$executableFiles = @()
if ($env:VARIANT -like 'generic*') {
$executableFiles += 'ArchiSteamFarm.sh', 'ArchiSteamFarm-Service.sh'
} elseif (($env:VARIANT -like 'linux*') -or ($env:VARIANT -like 'osx*')) {
$executableFiles += 'ArchiSteamFarm', 'ArchiSteamFarm-Service.sh'
}
foreach ($executableFile in $executableFiles) {
tools\zip_exec\zip_exec.exe "out\ASF-$env:VARIANT.zip" "$executableFile"
if ($LastExitCode -ne 0) {
throw "Last command failed."
}
}
}
- name: Upload ASF-${{ matrix.variant }}
uses: actions/upload-artifact@v3.1.2
with:
name: ${{ matrix.os }}_ASF-win-x64
path: out/ASF-win-x64.zip
name: ${{ matrix.os }}_ASF-${{ matrix.variant }}
path: out/ASF-${{ matrix.variant }}.zip
release:
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
needs: publish
needs: publish-asf
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.5.2
- name: Download ASF-generic artifact from ubuntu-latest
uses: actions/download-artifact@v3.0.1
uses: actions/download-artifact@v3.0.2
with:
name: ubuntu-latest_ASF-generic
path: out
- name: Download ASF-generic-netf artifact from windows-latest
uses: actions/download-artifact@v3.0.1
uses: actions/download-artifact@v3.0.2
with:
name: windows-latest_ASF-generic-netf
path: out
- name: Download ASF-linux-arm artifact from ubuntu-latest
uses: actions/download-artifact@v3.0.1
uses: actions/download-artifact@v3.0.2
with:
name: ubuntu-latest_ASF-linux-arm
path: out
- name: Download ASF-linux-arm64 artifact from ubuntu-latest
uses: actions/download-artifact@v3.0.1
uses: actions/download-artifact@v3.0.2
with:
name: ubuntu-latest_ASF-linux-arm64
path: out
- name: Download ASF-linux-x64 artifact from ubuntu-latest
uses: actions/download-artifact@v3.0.1
uses: actions/download-artifact@v3.0.2
with:
name: ubuntu-latest_ASF-linux-x64
path: out
- name: Download ASF-osx-arm64 artifact from macos-latest
uses: actions/download-artifact@v3.0.1
uses: actions/download-artifact@v3.0.2
with:
name: macos-latest_ASF-osx-arm64
path: out
- name: Download ASF-osx-x64 artifact from macos-latest
uses: actions/download-artifact@v3.0.1
uses: actions/download-artifact@v3.0.2
with:
name: macos-latest_ASF-osx-x64
path: out
- name: Download ASF-win-arm64 artifact from windows-latest
uses: actions/download-artifact@v3.0.2
with:
name: windows-latest_ASF-win-arm64
path: out
- name: Download ASF-win-x64 artifact from windows-latest
uses: actions/download-artifact@v3.0.1
uses: actions/download-artifact@v3.0.2
with:
name: windows-latest_ASF-win-x64
path: out
@@ -520,124 +491,23 @@ jobs:
)
- name: Upload SHA512SUMS
uses: actions/upload-artifact@v3.1.1
uses: actions/upload-artifact@v3.1.2
with:
name: SHA512SUMS
path: out/SHA512SUMS
- name: Upload SHA512SUMS.sign
uses: actions/upload-artifact@v3.1.1
uses: actions/upload-artifact@v3.1.2
with:
name: SHA512SUMS.sign
path: out/SHA512SUMS.sign
- name: Create ArchiSteamFarm GitHub release
id: github_release
uses: actions/create-release@v1.1.4
env:
GITHUB_TOKEN: ${{ secrets.ARCHIBOT_GITHUB_TOKEN }}
uses: ncipollo/release-action@v1.12.0
with:
tag_name: ${{ github.ref }}
release_name: ArchiSteamFarm V${{ github.ref }}
body_path: .github/RELEASE_TEMPLATE.md
artifacts: "out/*"
bodyFile: .github/RELEASE_TEMPLATE.md
makeLatest: false
name: ArchiSteamFarm V${{ github.ref_name }}
prerelease: true
- name: Upload ASF-generic to GitHub release
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.github_release.outputs.upload_url }}
asset_path: out/ASF-generic.zip
asset_name: ASF-generic.zip
asset_content_type: application/zip
- name: Upload ASF-generic-netf to GitHub release
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.github_release.outputs.upload_url }}
asset_path: out/ASF-generic-netf.zip
asset_name: ASF-generic-netf.zip
asset_content_type: application/zip
- name: Upload ASF-linux-arm to GitHub release
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.github_release.outputs.upload_url }}
asset_path: out/ASF-linux-arm.zip
asset_name: ASF-linux-arm.zip
asset_content_type: application/zip
- name: Upload ASF-linux-arm64 to GitHub release
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.github_release.outputs.upload_url }}
asset_path: out/ASF-linux-arm64.zip
asset_name: ASF-linux-arm64.zip
asset_content_type: application/zip
- name: Upload ASF-linux-x64 to GitHub release
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.github_release.outputs.upload_url }}
asset_path: out/ASF-linux-x64.zip
asset_name: ASF-linux-x64.zip
asset_content_type: application/zip
- name: Upload ASF-osx-arm64 to GitHub release
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.github_release.outputs.upload_url }}
asset_path: out/ASF-osx-arm64.zip
asset_name: ASF-osx-arm64.zip
asset_content_type: application/zip
- name: Upload ASF-osx-x64 to GitHub release
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.github_release.outputs.upload_url }}
asset_path: out/ASF-osx-x64.zip
asset_name: ASF-osx-x64.zip
asset_content_type: application/zip
- name: Upload ASF-win-x64 to GitHub release
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.github_release.outputs.upload_url }}
asset_path: out/ASF-win-x64.zip
asset_name: ASF-win-x64.zip
asset_content_type: application/zip
- name: Upload SHA512SUMS to GitHub release
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.github_release.outputs.upload_url }}
asset_path: out/SHA512SUMS
asset_name: SHA512SUMS
asset_content_type: text/plain
- name: Upload SHA512SUMS.sign to GitHub release
uses: actions/upload-release-asset@v1.0.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.github_release.outputs.upload_url }}
asset_path: out/SHA512SUMS.sign
asset_name: SHA512SUMS.sign
asset_content_type: text/plain
token: ${{ secrets.ARCHIBOT_GITHUB_TOKEN }}

View File

@@ -10,7 +10,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3.2.0
uses: actions/checkout@v3.5.2
with:
submodules: recursive
token: ${{ secrets.ARCHIBOT_GITHUB_TOKEN }}
@@ -26,7 +26,7 @@ jobs:
git reset --hard origin/master
- name: Download latest translations from Crowdin
uses: crowdin/github-action@1.5.2
uses: crowdin/github-action@v1.7.1
with:
upload_sources: false
download_translations: true
@@ -71,7 +71,7 @@ jobs:
run: |
set -eu
git add -A "ArchiSteamFarm/Localization" "ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization" "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization" "wiki"
git add -A "ArchiSteamFarm/Localization" "ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization" "ArchiSteamFarm.OfficialPlugins.MobileAuthenticator/Localization" "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization" "wiki"
if ! git diff --cached --quiet; then
git commit -m "Automatic translations update"

2
ASF-ui

Submodule ASF-ui updated: a4617d1457...d71555d6a2

View File

@@ -11,7 +11,7 @@
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481'">
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<!-- Madness is already included in netf build of ASF, so we don't need to emit it ourselves -->
<PackageReference Update="JustArchiNET.Madness" IncludeAssets="compile" />

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -9,7 +9,7 @@
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481'">
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<!-- Madness is already included in netf build of ASF, so we don't need to emit it ourselves -->
<PackageReference Update="JustArchiNET.Madness" IncludeAssets="compile" />
</ItemGroup>

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AngleSharp.XPath" IncludeAssets="compile" />
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="Newtonsoft.Json" IncludeAssets="compile" />
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<!-- Madness is already included in netf build of ASF, so we don't need to emit it ourselves -->
<PackageReference Update="JustArchiNET.Madness" IncludeAssets="compile" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481'">
<Reference Include="System.Net.Http" HintPath="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8.1\System.Net.Http.dll" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ArchiSteamFarm\ArchiSteamFarm.csproj" ExcludeAssets="all" Private="false" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,24 @@
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// |
// http://www.apache.org/licenses/LICENSE-2.0
// |
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
[assembly: CLSCompliant(false)]

View File

@@ -0,0 +1,30 @@
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// |
// http://www.apache.org/licenses/LICENSE-2.0
// |
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using Newtonsoft.Json;
namespace ArchiSteamFarm.CustomPlugins.SignInWithSteam.Data;
public sealed class SignInWithSteamRequest {
[JsonProperty(Required = Required.Always)]
public Uri RedirectURL { get; private set; } = null!;
}

View File

@@ -0,0 +1,32 @@
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// |
// http://www.apache.org/licenses/LICENSE-2.0
// |
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using Newtonsoft.Json;
namespace ArchiSteamFarm.CustomPlugins.SignInWithSteam.Data;
public sealed class SignInWithSteamResponse {
[JsonProperty(Required = Required.Always)]
public Uri ReturnURL { get; private set; }
internal SignInWithSteamResponse(Uri returnURL) => ReturnURL = returnURL ?? throw new ArgumentNullException(nameof(returnURL));
}

View File

@@ -0,0 +1,122 @@
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// |
// http://www.apache.org/licenses/LICENSE-2.0
// |
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Globalization;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using AngleSharp.Dom;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.CustomPlugins.SignInWithSteam.Data;
using ArchiSteamFarm.IPC.Controllers.Api;
using ArchiSteamFarm.IPC.Responses;
using ArchiSteamFarm.Localization;
using ArchiSteamFarm.Steam;
using ArchiSteamFarm.Steam.Integration;
using ArchiSteamFarm.Web;
using ArchiSteamFarm.Web.Responses;
using Microsoft.AspNetCore.Mvc;
namespace ArchiSteamFarm.CustomPlugins.SignInWithSteam;
[Route("/Api/Bot/{botName:required}/SignInWithSteam")]
public sealed class SignInWithSteamController : ArchiController {
[HttpPost]
[ProducesResponseType(typeof(GenericResponse<SignInWithSteamResponse>), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.ServiceUnavailable)]
public async Task<ActionResult<GenericResponse>> Post(string botName, [FromBody] SignInWithSteamRequest request) {
if (string.IsNullOrEmpty(botName)) {
throw new ArgumentNullException(nameof(botName));
}
ArgumentNullException.ThrowIfNull(request);
Bot? bot = Bot.GetBot(botName);
if (bot == null) {
return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botName)));
}
if (!bot.IsConnectedAndLoggedOn) {
return StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false, Strings.BotNotConnected));
}
// We've got a redirection, initiate OpenID procedure by following it
using HtmlDocumentResponse? challengeResponse = await bot.ArchiWebHandler.UrlGetToHtmlDocumentWithSession(request.RedirectURL).ConfigureAwait(false);
if (challengeResponse?.Content == null) {
return StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
}
IAttr? paramsNode = challengeResponse.Content.SelectSingleNode<IAttr>("//input[@name='openidparams']/@value");
if (paramsNode == null) {
ASF.ArchiLogger.LogNullError(paramsNode);
return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(paramsNode))));
}
string paramsValue = paramsNode.Value;
if (string.IsNullOrEmpty(paramsValue)) {
ASF.ArchiLogger.LogNullError(paramsValue);
return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(paramsValue))));
}
IAttr? nonceNode = challengeResponse.Content.SelectSingleNode<IAttr>("//input[@name='nonce']/@value");
if (nonceNode == null) {
ASF.ArchiLogger.LogNullError(nonceNode);
return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(nonceNode))));
}
string nonceValue = nonceNode.Value;
if (string.IsNullOrEmpty(nonceValue)) {
ASF.ArchiLogger.LogNullError(nonceValue);
return StatusCode((int) HttpStatusCode.InternalServerError, new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorObjectIsNull, nameof(nonceValue))));
}
Uri loginRequest = new(ArchiWebHandler.SteamCommunityURL, "/openid/login");
using StringContent actionContent = new("steam_openid_login");
using StringContent modeContent = new("checkid_setup");
using StringContent paramsContent = new(paramsValue);
using StringContent nonceContent = new(nonceValue);
using MultipartFormDataContent data = new();
data.Add(actionContent, "action");
data.Add(modeContent, "openid.mode");
data.Add(paramsContent, "openidparams");
data.Add(nonceContent, "nonce");
// Accept OpenID request presented and follow redirection back to the data we initially expected
BasicResponse? loginResponse = await bot.ArchiWebHandler.WebBrowser.UrlPost(loginRequest, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnRedirections).ConfigureAwait(false);
return loginResponse != null ? Ok(new GenericResponse<SignInWithSteamResponse>(new SignInWithSteamResponse(loginResponse.FinalUri))) : StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
}
}

View File

@@ -0,0 +1,43 @@
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// |
// http://www.apache.org/licenses/LICENSE-2.0
// |
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Composition;
using System.Threading.Tasks;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.Plugins.Interfaces;
using JetBrains.Annotations;
namespace ArchiSteamFarm.CustomPlugins.SignInWithSteam;
[Export(typeof(IPlugin))]
[UsedImplicitly]
internal sealed class SignInWithSteamPlugin : IPlugin {
public string Name => nameof(SignInWithSteamPlugin);
public Version Version => typeof(SignInWithSteamPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));
public Task OnLoaded() {
ASF.ArchiLogger.LogGenericInfo("Loaded!");
return Task.CompletedTask;
}
}

View File

@@ -13,10 +13,12 @@
<PackageReference Include="System.Linq.Async" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481'">
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<!-- Madness is already included in netf build of ASF, so we don't need to emit it ourselves -->
<PackageReference Update="JustArchiNET.Madness" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481'">
<Reference Include="System.Net.Http" HintPath="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8.1\System.Net.Http.dll" />
</ItemGroup>

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,12 +33,16 @@ using ArchiSteamFarm.Steam.Storage;
using ArchiSteamFarm.Storage;
using ArchiSteamFarm.Web;
using ArchiSteamFarm.Web.Responses;
using SteamKit2;
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
internal static class Backend {
internal static async Task<BasicResponse?> AnnounceForListing(Bot bot, WebBrowser webBrowser, IReadOnlyList<Asset> inventory, IReadOnlyCollection<Asset.EType> acceptedMatchableTypes, string tradeToken, string? nickname = null, string? avatarHash = null) {
ArgumentNullException.ThrowIfNull(bot);
internal static async Task<BasicResponse?> AnnounceForListing(ulong steamID, WebBrowser webBrowser, IReadOnlyList<AssetForListing> inventory, IReadOnlyCollection<Asset.EType> acceptedMatchableTypes, uint totalInventoryCount, bool matchEverything, string tradeToken, string? nickname = null, string? avatarHash = null) {
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
throw new ArgumentOutOfRangeException(nameof(steamID));
}
ArgumentNullException.ThrowIfNull(webBrowser);
if ((inventory == null) || (inventory.Count == 0)) {
@@ -49,6 +53,10 @@ internal static class Backend {
throw new ArgumentNullException(nameof(acceptedMatchableTypes));
}
if (totalInventoryCount == 0) {
throw new ArgumentOutOfRangeException(nameof(totalInventoryCount));
}
if (string.IsNullOrEmpty(tradeToken)) {
throw new ArgumentNullException(nameof(tradeToken));
}
@@ -57,11 +65,11 @@ internal static class Backend {
throw new ArgumentOutOfRangeException(nameof(tradeToken));
}
Uri request = new(ArchiNet.URL, "/Api/Listing/Announce");
Uri request = new(ArchiNet.URL, "/Api/Listing/Announce/v3");
AnnouncementRequest data = new(ASF.GlobalDatabase?.Identifier ?? Guid.NewGuid(), bot.SteamID, tradeToken, inventory, acceptedMatchableTypes, bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything), ASF.GlobalConfig?.MaxTradeHoldDuration ?? GlobalConfig.DefaultMaxTradeHoldDuration, nickname, avatarHash);
AnnouncementRequest data = new(ASF.GlobalDatabase?.Identifier ?? Guid.NewGuid(), steamID, tradeToken, inventory, acceptedMatchableTypes, totalInventoryCount, matchEverything, ASF.GlobalConfig?.MaxTradeHoldDuration ?? GlobalConfig.DefaultMaxTradeHoldDuration, nickname, avatarHash);
return await webBrowser.UrlPost(request, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnRedirections | WebBrowser.ERequestOptions.ReturnClientErrors).ConfigureAwait(false);
return await webBrowser.UrlPost(request, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnRedirections | WebBrowser.ERequestOptions.ReturnClientErrors | WebBrowser.ERequestOptions.CompressRequest).ConfigureAwait(false);
}
internal static async Task<(HttpStatusCode StatusCode, ImmutableHashSet<ListedUser> Users)?> GetListedUsersForMatching(Guid licenseID, Bot bot, WebBrowser webBrowser, IReadOnlyCollection<Asset> inventory, IReadOnlyCollection<Asset.EType> acceptedMatchableTypes) {
@@ -80,7 +88,7 @@ internal static class Backend {
throw new ArgumentNullException(nameof(acceptedMatchableTypes));
}
Uri request = new(ArchiNet.URL, "/Api/Listing/Inventories");
Uri request = new(ArchiNet.URL, "/Api/Listing/Inventories/v2");
Dictionary<string, string> headers = new(1, StringComparer.Ordinal) {
{ "X-License-Key", licenseID.ToString("N") }
@@ -88,7 +96,7 @@ internal static class Backend {
InventoriesRequest data = new(ASF.GlobalDatabase?.Identifier ?? Guid.NewGuid(), bot.SteamID, inventory, acceptedMatchableTypes);
ObjectResponse<GenericResponse<ImmutableHashSet<ListedUser>>>? response = await webBrowser.UrlPostToJsonObject<GenericResponse<ImmutableHashSet<ListedUser>>, InventoriesRequest>(request, headers, data, requestOptions: WebBrowser.ERequestOptions.ReturnClientErrors | WebBrowser.ERequestOptions.AllowInvalidBodyOnErrors).ConfigureAwait(false);
ObjectResponse<GenericResponse<ImmutableHashSet<ListedUser>>>? response = await webBrowser.UrlPostToJsonObject<GenericResponse<ImmutableHashSet<ListedUser>>, InventoriesRequest>(request, headers, data, requestOptions: WebBrowser.ERequestOptions.ReturnClientErrors | WebBrowser.ERequestOptions.AllowInvalidBodyOnErrors | WebBrowser.ERequestOptions.CompressRequest).ConfigureAwait(false);
if (response == null) {
return null;
@@ -105,6 +113,6 @@ internal static class Backend {
HeartBeatRequest data = new(ASF.GlobalDatabase?.Identifier ?? Guid.NewGuid(), bot.SteamID);
return await webBrowser.UrlPost(request, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnRedirections | WebBrowser.ERequestOptions.ReturnClientErrors).ConfigureAwait(false);
return await webBrowser.UrlPost(request, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnRedirections | WebBrowser.ERequestOptions.ReturnClientErrors | WebBrowser.ERequestOptions.CompressRequest).ConfigureAwait(false);
}
}

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,7 +22,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using ArchiSteamFarm.Steam.Data;
using ArchiSteamFarm.Steam.Storage;
using JetBrains.Annotations;
@@ -39,7 +38,7 @@ internal sealed class AnnouncementRequest {
private readonly Guid Guid;
[JsonProperty(Required = Required.Always)]
private readonly ImmutableHashSet<AssetForListing> Inventory;
private readonly ImmutableList<AssetForListing> Inventory;
[JsonProperty(Required = Required.Always)]
private readonly ImmutableHashSet<Asset.EType> MatchableTypes;
@@ -56,10 +55,13 @@ internal sealed class AnnouncementRequest {
[JsonProperty(Required = Required.Always)]
private readonly ulong SteamID;
[JsonProperty(Required = Required.Always)]
private readonly uint TotalInventoryCount;
[JsonProperty(Required = Required.Always)]
private readonly string TradeToken;
internal AnnouncementRequest(Guid guid, ulong steamID, string tradeToken, IReadOnlyList<Asset> inventory, IReadOnlyCollection<Asset.EType> matchableTypes, bool matchEverything, byte maxTradeHoldDuration, string? nickname = null, string? avatarHash = null) {
internal AnnouncementRequest(Guid guid, ulong steamID, string tradeToken, IReadOnlyList<AssetForListing> inventory, IReadOnlyCollection<Asset.EType> matchableTypes, uint totalInventoryCount, bool matchEverything, byte maxTradeHoldDuration, string? nickname = null, string? avatarHash = null) {
if (guid == Guid.Empty) {
throw new ArgumentOutOfRangeException(nameof(guid));
}
@@ -84,15 +86,18 @@ internal sealed class AnnouncementRequest {
throw new ArgumentNullException(nameof(matchableTypes));
}
uint index = 0;
if (totalInventoryCount == 0) {
throw new ArgumentOutOfRangeException(nameof(totalInventoryCount));
}
Guid = guid;
SteamID = steamID;
TradeToken = tradeToken;
Inventory = inventory.Select(asset => new AssetForListing(asset, index++)).ToImmutableHashSet();
Inventory = inventory.ToImmutableList();
MatchableTypes = matchableTypes.ToImmutableHashSet();
MatchEverything = matchEverything;
MaxTradeHoldDuration = maxTradeHoldDuration;
TotalInventoryCount = totalInventoryCount;
Nickname = nickname;
AvatarHash = avatarHash;

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,12 +26,12 @@ using Newtonsoft.Json;
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
internal sealed class AssetForListing : AssetInInventory {
[JsonProperty(Required = Required.Always)]
internal readonly uint Index;
[JsonProperty("l", Required = Required.Always)]
internal readonly ulong PreviousAssetID;
internal AssetForListing(Asset asset, uint index) : base(asset) {
internal AssetForListing(Asset asset, ulong previousAssetID) : base(asset) {
ArgumentNullException.ThrowIfNull(asset);
Index = index;
PreviousAssetID = previousAssetID;
}
}

View File

@@ -0,0 +1,62 @@
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// |
// http://www.apache.org/licenses/LICENSE-2.0
// |
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using ArchiSteamFarm.Steam.Data;
using Newtonsoft.Json;
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
internal class AssetForMatching {
[JsonProperty("a", Required = Required.Always)]
internal readonly uint Amount;
[JsonProperty("c", Required = Required.Always)]
internal readonly ulong ClassID;
[JsonProperty("r", Required = Required.Always)]
internal readonly Asset.ERarity Rarity;
[JsonProperty("e", Required = Required.Always)]
internal readonly uint RealAppID;
[JsonProperty("t", Required = Required.Always)]
internal readonly bool Tradable;
[JsonProperty("p", Required = Required.Always)]
internal readonly Asset.EType Type;
internal AssetForMatching(Asset asset) {
ArgumentNullException.ThrowIfNull(asset);
Amount = asset.Amount;
ClassID = asset.ClassID;
Tradable = asset.Tradable;
RealAppID = asset.RealAppID;
Type = asset.Type;
Rarity = asset.Rarity;
}
[JsonConstructor]
protected AssetForMatching() { }
}

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,40 +25,14 @@ using Newtonsoft.Json;
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
internal class AssetInInventory {
[JsonProperty(Required = Required.Always)]
internal readonly uint Amount;
[JsonProperty(Required = Required.Always)]
internal class AssetInInventory : AssetForMatching {
[JsonProperty("d", Required = Required.Always)]
internal readonly ulong AssetID;
[JsonProperty(Required = Required.Always)]
internal readonly ulong ClassID;
[JsonProperty(Required = Required.Always)]
internal readonly Asset.ERarity Rarity;
[JsonProperty(Required = Required.Always)]
internal readonly uint RealAppID;
[JsonProperty(Required = Required.Always)]
internal readonly bool Tradable;
[JsonProperty(Required = Required.Always)]
internal readonly Asset.EType Type;
internal AssetInInventory(Asset asset) {
internal AssetInInventory(Asset asset) : base(asset) {
ArgumentNullException.ThrowIfNull(asset);
AssetID = asset.AssetID;
Amount = asset.Amount;
ClassID = asset.ClassID;
Tradable = asset.Tradable;
RealAppID = asset.RealAppID;
Type = asset.Type;
Rarity = asset.Rarity;
}
[JsonConstructor]

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,7 +34,7 @@ internal sealed class InventoriesRequest {
internal readonly Guid Guid;
[JsonProperty(Required = Required.Always)]
internal readonly ImmutableHashSet<AssetInInventory> Inventory;
internal readonly ImmutableHashSet<AssetForMatching> Inventory;
[JsonProperty(Required = Required.Always)]
internal readonly ImmutableHashSet<Asset.EType> MatchableTypes;
@@ -61,7 +61,7 @@ internal sealed class InventoriesRequest {
Guid = guid;
SteamID = steamID;
Inventory = inventory.Select(static asset => new AssetInInventory(asset)).ToImmutableHashSet();
Inventory = inventory.Select(static asset => new AssetForMatching(asset)).ToImmutableHashSet();
MatchableTypes = matchableTypes.ToImmutableHashSet();
}
}

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -55,6 +55,11 @@ internal sealed class ListedUser {
internal readonly ulong SteamID;
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
#pragma warning disable CS0649 // False positive, the field is used during json deserialization
[JsonProperty(Required = Required.Always)]
internal readonly uint TotalInventoryCount;
#pragma warning restore CS0649 // False positive, the field is used during json deserialization
[JsonProperty(Required = Required.Always)]
internal readonly string TradeToken = "";

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,6 +31,7 @@ using ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Localization;
using ArchiSteamFarm.Plugins;
using ArchiSteamFarm.Plugins.Interfaces;
using ArchiSteamFarm.Steam;
using ArchiSteamFarm.Steam.Exchange;
using ArchiSteamFarm.Steam.Integration.Callbacks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -39,7 +40,7 @@ using SteamKit2;
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
[Export(typeof(IPlugin))]
internal sealed class ItemsMatcherPlugin : OfficialPlugin, IBot, IBotCommand2, IBotIdentity, IBotModules, IBotUserNotifications {
internal sealed class ItemsMatcherPlugin : OfficialPlugin, IBot, IBotCommand2, IBotIdentity, IBotModules, IBotTradeOfferResults, IBotUserNotifications {
internal static readonly ConcurrentDictionary<Bot, RemoteCommunication> RemoteCommunications = new();
[JsonProperty]
@@ -98,6 +99,23 @@ internal sealed class ItemsMatcherPlugin : OfficialPlugin, IBot, IBotCommand2, I
}
}
public Task OnBotTradeOfferResults(Bot bot, IReadOnlyCollection<ParseTradeResult> tradeResults) {
ArgumentNullException.ThrowIfNull(bot);
if ((tradeResults == null) || (tradeResults.Count == 0)) {
throw new ArgumentNullException(nameof(tradeResults));
}
// We're interested only in Items notification for Bot that has RemoteCommunication enabled
if (!RemoteCommunications.TryGetValue(bot, out RemoteCommunication? remoteCommunication) || !tradeResults.Any(tradeResult => tradeResult is { Result: ParseTradeResult.EResult.Accepted, Confirmed: true } && ((tradeResult.ItemsToGive?.Any(item => bot.BotConfig.MatchableTypes.Contains(item.Type)) == true) || (tradeResult.ItemsToReceive?.Any(item => bot.BotConfig.MatchableTypes.Contains(item.Type)) == true)))) {
return Task.CompletedTask;
}
remoteCommunication.OnNewItemsNotification();
return Task.CompletedTask;
}
public Task OnBotUserNotifications(Bot bot, IReadOnlyCollection<UserNotificationsCallback.EUserNotification> newNotifications) {
ArgumentNullException.ThrowIfNull(bot);

View File

@@ -68,5 +68,11 @@ namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Localization {
return ResourceManager.GetString("TradeOfferFailed", resourceCulture);
}
}
internal static string ActivelyMatchingSomeConfirmationsFailed {
get {
return ResourceManager.GetString("ActivelyMatchingSomeConfirmationsFailed", resourceCulture);
}
}
}
}

View File

@@ -66,4 +66,20 @@
<value>Съвпадащи общо {0} комплекта този кръг.</value>
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="ListingAnnouncing" xml:space="preserve">
<value>Обявяване на {0} ({1}) с инвентар, съставен от общо {2} артикула в обявата...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
</data>
<data name="MatchingFound" xml:space="preserve">
<value>Съпоставихте общо {0} артикула с бот {1} ({2}), изпращайки трейд оферта...</value>
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>
</data>
<data name="TradeOfferFailed" xml:space="preserve">
<value>Неуспешно изпращане на трейд оферта до бот {0} ({1}), продължаваме...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Някои потвърждения са неуспешни, приблизително {0} от {1} от размените бяха изпратени успешно.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -78,4 +78,8 @@
<value>Nepodařilo se odeslat obchodní nabídku pro bota {0} ({1}), pokračuji...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Některá potvrzení se nezdařila, úspěšně bylo odesláno přibližně {0} z {1} obchodů.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -66,4 +66,20 @@
<value>Insgesamt wurden in diesem Durchgang {0} Set(s) abgeglichen.</value>
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="ListingAnnouncing" xml:space="preserve">
<value>Gebe Benutzerkonto {0} ({1}) mit insgesamt aus {2} Gegenständen bestehendem Inventar bekannt...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
</data>
<data name="MatchingFound" xml:space="preserve">
<value>{0} passende Gegenstände bei Bot {1} ({2}) gefunden, sende Handelsangebot...</value>
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>
</data>
<data name="TradeOfferFailed" xml:space="preserve">
<value>Fehler beim Senden eines Handelsangebots an Bot {0} ({1}), überspringe...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Einige Bestätigungen sind fehlgeschlagen, etwa {0} von {1} Transaktionen wurden erfolgreich versendet.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -67,7 +67,7 @@
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="ListingAnnouncing" xml:space="preserve">
<value>Anunciando {0} ({1}) con inventario compuesto por {2} artículos en total en el listado.</value>
<value>Anunciando en el listado a {0} ({1}) con un inventario compuesto por {2} artículos en total.</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
</data>
<data name="MatchingFound" xml:space="preserve">
@@ -78,4 +78,8 @@
<value>Error al enviar la oferta de intercambio al bot {0} ({1}), continuando...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Algunas confirmaciones han fallado, aproximadamente {0} de {1} intercambios fueron enviados exitosamente.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -62,4 +62,20 @@
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
<value>در این دور جمعاً {0} ست مطابقت داده شد.</value>
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="MatchingFound" xml:space="preserve">
<value>در مجموع {0} مورد با ربات {1} ({2}) مطابقت داده شد، درحال ارسال ترید...</value>
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>
</data>
<data name="TradeOfferFailed" xml:space="preserve">
<value>ارسال ترید به ربات {0} ({1}) شکست خورد، درحال ادامه دادن...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>بعضی از تاییدیه ها شکست خورد، تقریبا {0} تا از {1} ترید با موفقیت ارسال شدند.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -62,4 +62,20 @@
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
<value>התאימו בסך הכל {0} ערכות בסיבוב זה.</value>
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="ListingAnnouncing" xml:space="preserve">
<value>מכריז על {0} ({1}) עם מלאי מורכב מ-{2} פריטים בסך הכל ברישום...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
</data>
<data name="MatchingFound" xml:space="preserve">
<value>התאים סך של {0} פריטים לבוט {1} ({2}), שולח הצעת סחר...</value>
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>
</data>
<data name="TradeOfferFailed" xml:space="preserve">
<value>נכשל שליחת הצעת סחר לבוט {0} ({1}), ממשיך הלאה...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
</root>

View File

@@ -66,4 +66,20 @@
<value>Kopā salīdzināti {0} seti šajā raundā.</value>
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="ListingAnnouncing" xml:space="preserve">
<value>Paziņojam {0} ({1}) inventāru, kas kopumā sastāv no {2} lietām, sarakstā...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
</data>
<data name="MatchingFound" xml:space="preserve">
<value>Sakrita kopumā {0} lietas ar botu {1} ({2}), sūta darījuma pieprasījumu...</value>
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>
</data>
<data name="TradeOfferFailed" xml:space="preserve">
<value>Neizdevās nosūtīt darījuma piedāvājumu botam {0} ({1}), turpinam tālāk...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Daži apstiprinājumi nav izdevušies, aptuveni {0} no {1} darījumiem tika veiksmīgi nosūtīti.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -66,4 +66,20 @@
<value>Deze ronde zijn in totaal {0} sets gematcht.</value>
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="ListingAnnouncing" xml:space="preserve">
<value>Mededeling van {0} ({1}) met een inventaris gemaakt van in totaal {2} items op de lijst...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
</data>
<data name="MatchingFound" xml:space="preserve">
<value>In totaal {0} items gekoppeld aan bot {1} ({2}), handelsaanbieding verzonden...</value>
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>
</data>
<data name="TradeOfferFailed" xml:space="preserve">
<value>Fout bij het verzenden van een transactie aanbod aan bot {0} ({1}), verder gaan...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Sommige bevestigingen zijn mislukt, ongeveer {0} van de {1} transacties zijn succesvol verzonden.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -78,4 +78,8 @@
<value>Nie udało się wysłać oferty wymiany do bota {0} ({1}), przechodzenie dalej...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Niektóre potwierdzenia nie powiodły się, około {0} z {1} transakcji zostało wysłanych pomyślnie.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -78,4 +78,8 @@
<value>Falha ao enviar uma oferta de troca para o bot {0} ({1}), prosseguindo...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Algumas confirmações falharam, cerca de {0} de {1} operações foram enviadas com sucesso.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -66,4 +66,20 @@
<value>Corresponde a um total de {0} conjuntos nesta rodada.</value>
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="ListingAnnouncing" xml:space="preserve">
<value>Anunciando {0} ({1}) com um inventário composto por {2} itens no total na listagem...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
</data>
<data name="MatchingFound" xml:space="preserve">
<value>Foi confirmando um total de {0} itens com o bot {1} ({2}), a enviar oferta de troca...</value>
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>
</data>
<data name="TradeOfferFailed" xml:space="preserve">
<value>Falha ao enviar uma oferta de troca para o bot {0} ({1}), a avançar...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Algumas confirmações falharam, aproximadamente {0} de {1} trocas foram enviadas com sucesso.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -78,4 +78,8 @@
<value>FAILD 2 SEND TRADE OFFR 2 BOT {0} ({1}), MOVIN ON...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>SUM CONFIRMASHUNS HAS FAILD, APPROXIMATELY {0} OUT OV {1} TRADEZ WUZ SENT SUCCESFULLY.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -78,4 +78,8 @@
<value>Failed to send a trade offer to bot {0} ({1}), moving on...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Some confirmations have failed, approximately {0} out of {1} trades were sent successfully.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -78,4 +78,8 @@
<value>Не удалось отправить предложение о сделке боту {0} ({1}), переходим в...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Некоторые подтверждения не удались - примерно {0} трейдов из {1} были успешно отправлены.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -63,7 +63,23 @@
</value>
</resheader>
<data name="ActivelyMatchingItemsRound" xml:space="preserve">
<value>За цей раунд зібрано {0} наборів карток.</value>
<value>Загальна кількість наборів у цьому раунді: {0}.</value>
<comment>{0} will be replaced by number of sets traded</comment>
</data>
<data name="ListingAnnouncing" xml:space="preserve">
<value>Оголошення від {0} ({1}) із загальною кількістю товарів у списку: {2}...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory</comment>
</data>
<data name="MatchingFound" xml:space="preserve">
<value>Всього зібрано {0} предметів за допомогою бота {1} ({2}), надсилаю пропозицію обміну...</value>
<comment>{0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname</comment>
</data>
<data name="TradeOfferFailed" xml:space="preserve">
<value>Не вдалося відправити пропозицію обміну боту {0} ({1}), йдемо далі...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Деякі підтвердження завершилися невдачею, приблизно {0} з {1} угод були відправлені успішно.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -78,4 +78,8 @@
<value>Thất bại khi gửi đề nghị trao đổi tới bot {0} ({1}), đang tiếp tục...</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>Một số xác nhận thất bại, khoảng {0} trong số {1} giao dịch đã được gửi thành công.</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -78,4 +78,8 @@
<value>向机器人 {0}{1})发送交易报价失败,正在继续…</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>部分确认失败,{1} 个交易中约有 {0} 个发送成功。</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -78,4 +78,8 @@
<value>無法向 Bot {0}{1})發送交易提案,正在繼續…</value>
<comment>{0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'</comment>
</data>
<data name="ActivelyMatchingSomeConfirmationsFailed" xml:space="preserve">
<value>部分交易失敗,{1} 個交易中約 {0} 個發送成功。</value>
<comment>{0} will be replaced by amount of the trade offers that succeeded (number), {1} will be replaced by amount of the trade offers that were supposed to be sent in total (number)</comment>
</data>
</root>

View File

@@ -4,7 +4,7 @@
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,6 +29,7 @@ using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.Helpers;
using ArchiSteamFarm.Localization;
using ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Data;
using ArchiSteamFarm.Steam;
@@ -41,14 +42,17 @@ using ArchiSteamFarm.Steam.Storage;
using ArchiSteamFarm.Storage;
using ArchiSteamFarm.Web;
using ArchiSteamFarm.Web.Responses;
using Newtonsoft.Json.Linq;
using SteamKit2;
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
private const byte MaxAnnouncementTTL = 60; // Maximum amount of minutes we can wait before the next Announcement
private const string MatchActivelyTradeOfferIDsStorageKey = $"{nameof(ItemsMatcher)}-{nameof(MatchActively)}-TradeOfferIDs";
private const byte MaxAnnouncementTTL = 60; // Maximum amount of minutes we can wait if the next announcement doesn't happen naturally
private const byte MaxTradeOffersActive = 10; // The actual upper limit is 30, but we should use lower amount to allow some bots to react before we hit the maximum allowed
private const byte MinAnnouncementTTL = 5; // Minimum amount of minutes we must wait before the next Announcement
private const byte MinHeartBeatTTL = 10; // Minimum amount of minutes we must wait before sending next HeartBeat
private const byte MinItemsCount = 100; // Minimum amount of items to be eligible for public listing
private const byte MinPersonaStateTTL = 5; // Minimum amount of minutes we must wait before requesting persona state update
private static readonly ImmutableHashSet<Asset.EType> AcceptedMatchableTypes = ImmutableHashSet.Create(
@@ -60,11 +64,16 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
private readonly Bot Bot;
private readonly Timer? HeartBeatTimer;
// We access this collection only within a semaphore, therefore there is no need for concurrent access
private readonly Dictionary<ulong, uint> LastAnnouncedItems = new();
private readonly SemaphoreSlim MatchActivelySemaphore = new(1, 1);
private readonly Timer? MatchActivelyTimer;
private readonly SemaphoreSlim RequestsSemaphore = new(1, 1);
private readonly WebBrowser? WebBrowser;
private readonly WebBrowser WebBrowser;
private string? LastAnnouncedTradeToken;
private DateTime LastAnnouncement;
private DateTime LastHeartBeat;
private DateTime LastPersonaStateRequest;
@@ -76,14 +85,9 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
ArgumentNullException.ThrowIfNull(bot);
Bot = bot;
if (!Bot.BotConfig.RemoteCommunication.HasFlag(BotConfig.ERemoteCommunication.PublicListing) && !Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchActively)) {
return;
}
WebBrowser = new WebBrowser(bot.ArchiLogger, ASF.GlobalConfig?.WebProxy, true);
if (Bot.BotConfig.RemoteCommunication.HasFlag(BotConfig.ERemoteCommunication.PublicListing)) {
if (Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.SteamTradeMatcher) && Bot.BotConfig.RemoteCommunication.HasFlag(BotConfig.ERemoteCommunication.PublicListing)) {
HeartBeatTimer = new Timer(
HeartBeat,
null,
@@ -110,6 +114,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
// Those are objects that are always being created if constructor doesn't throw exception
MatchActivelySemaphore.Dispose();
RequestsSemaphore.Dispose();
WebBrowser.Dispose();
// Those are objects that might be null and the check should be in-place
HeartBeatTimer?.Dispose();
@@ -120,16 +125,10 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
MatchActivelyTimer.Dispose();
}
}
WebBrowser?.Dispose();
}
public async ValueTask DisposeAsync() {
// Those are objects that are always being created if constructor doesn't throw exception
MatchActivelySemaphore.Dispose();
RequestsSemaphore.Dispose();
// Those are objects that might be null and the check should be in-place
// Dispose timers first so we won't launch new events
if (HeartBeatTimer != null) {
await HeartBeatTimer.DisposeAsync().ConfigureAwait(false);
}
@@ -141,7 +140,13 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
}
}
WebBrowser?.Dispose();
// Ensure the semaphores are closed, then dispose the rest
await MatchActivelySemaphore.WaitAsync().ConfigureAwait(false);
await RequestsSemaphore.WaitAsync().ConfigureAwait(false);
MatchActivelySemaphore.Dispose();
RequestsSemaphore.Dispose();
WebBrowser.Dispose();
}
internal void OnNewItemsNotification() => ShouldSendAnnouncementEarlier = true;
@@ -151,11 +156,12 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
return;
}
if (WebBrowser == null) {
throw new InvalidOperationException(nameof(WebBrowser));
if ((DateTime.UtcNow < LastAnnouncement.AddMinutes(ShouldSendAnnouncementEarlier ? MinAnnouncementTTL : MaxAnnouncementTTL)) && ShouldSendHeartBeats) {
return;
}
if ((DateTime.UtcNow < LastAnnouncement.AddMinutes(ShouldSendAnnouncementEarlier ? MinAnnouncementTTL : MaxAnnouncementTTL)) && ShouldSendHeartBeats) {
if (MatchActivelySemaphore.CurrentCount == 0) {
// We shouldn't bother with announcements while we're matching, it can wait until we're done
return;
}
@@ -166,6 +172,11 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
return;
}
if (MatchActivelySemaphore.CurrentCount == 0) {
// We shouldn't bother with announcements while we're matching, it can wait until we're done
return;
}
// Don't announce if we don't meet conditions
bool? eligible = await IsEligibleForListing().ConfigureAwait(false);
@@ -205,6 +216,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
return;
}
// We require to fetch whole inventory as a list here, as we need to know the order for calculating index and previousAssetID
List<Asset> inventory;
try {
@@ -225,8 +237,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
return;
}
// This is actual inventory
if (inventory.Count(item => item.Tradable && acceptedMatchableTypes.Contains(item.Type)) < MinItemsCount) {
if (inventory.Count == 0) {
// We're not eligible, record this as a valid check
LastAnnouncement = DateTime.UtcNow;
ShouldSendAnnouncementEarlier = ShouldSendHeartBeats = false;
@@ -234,6 +245,67 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
return;
}
bool matchEverything = Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything);
ulong previousAssetID = 0;
List<AssetForListing> assetsForListing = new();
Dictionary<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity), bool> tradableSets = new();
foreach (Asset item in inventory) {
if (acceptedMatchableTypes.Contains(item.Type)) {
// Only tradable assets matter for MatchEverything bots
if (!matchEverything || item.Tradable) {
assetsForListing.Add(new AssetForListing(item, previousAssetID));
}
// But even for Fair bots, we should track and skip sets where we don't have any item to trade with
if (!matchEverything) {
(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity) key = (item.RealAppID, item.Type, item.Rarity);
if (tradableSets.TryGetValue(key, out bool tradable)) {
if (!tradable && item.Tradable) {
tradableSets[key] = true;
}
} else {
tradableSets[key] = item.Tradable;
}
}
}
previousAssetID = item.AssetID;
}
if (assetsForListing.Count == 0) {
// We're not eligible, record this as a valid check
LastAnnouncement = DateTime.UtcNow;
ShouldSendAnnouncementEarlier = ShouldSendHeartBeats = false;
return;
}
// We can now skip sets where we don't have any item to trade with, MatchEverything bots are already filtered to tradable only
if (!matchEverything) {
assetsForListing.RemoveAll(item => tradableSets.TryGetValue((item.RealAppID, item.Type, item.Rarity), out bool tradable) && !tradable);
if (assetsForListing.Count == 0) {
// We're not eligible, record this as a valid check
LastAnnouncement = DateTime.UtcNow;
ShouldSendAnnouncementEarlier = ShouldSendHeartBeats = false;
return;
}
}
if (ShouldSendHeartBeats && (tradeToken == LastAnnouncedTradeToken) && (assetsForListing.Count == LastAnnouncedItems.Count) && assetsForListing.All(item => LastAnnouncedItems.TryGetValue(item.AssetID, out uint amount) && (item.Amount == amount))) {
// There is nothing new to announce, this is fine, skip the request
LastAnnouncement = DateTime.UtcNow;
ShouldSendAnnouncementEarlier = false;
return;
}
if (!SignedInWithSteam) {
HttpStatusCode? signInWithSteam = await ArchiNet.SignInWithSteam(Bot, WebBrowser).ConfigureAwait(false);
@@ -255,10 +327,10 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
SignedInWithSteam = true;
}
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ListingAnnouncing, Bot.SteamID, nickname, inventory.Count));
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ListingAnnouncing, Bot.SteamID, nickname ?? Bot.SteamID.ToString(CultureInfo.InvariantCulture), assetsForListing.Count));
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
BasicResponse? response = await Backend.AnnounceForListing(Bot, WebBrowser, inventory, acceptedMatchableTypes, tradeToken!, nickname, avatarHash).ConfigureAwait(false);
BasicResponse? response = await Backend.AnnounceForListing(Bot.SteamID, WebBrowser, assetsForListing, acceptedMatchableTypes, (uint) inventory.Count, matchEverything, tradeToken!, nickname, avatarHash).ConfigureAwait(false);
if (response == null) {
// This is actually a network failure, so we'll stop sending heartbeats but not record it as valid check
@@ -298,7 +370,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
LastAnnouncement = DateTime.UtcNow.AddYears(1);
return;
#if NETFRAMEWORK
#if NETFRAMEWORK || NETSTANDARD
case (HttpStatusCode) 429:
#else
case HttpStatusCode.TooManyRequests:
@@ -320,10 +392,19 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
ShouldSendAnnouncementEarlier = false;
ShouldSendHeartBeats = true;
Bot.ArchiLogger.LogGenericInfo(Strings.Success);
LastAnnouncedTradeToken = tradeToken;
LastAnnouncedItems.Clear();
foreach (AssetForListing item in assetsForListing) {
LastAnnouncedItems[item.AssetID] = item.Amount;
}
LastAnnouncedItems.TrimExcess();
} finally {
RequestsSemaphore.Release();
}
Bot.ArchiLogger.LogGenericInfo(Strings.Success);
}
internal void TriggerMatchActivelyEarlier() {
@@ -338,10 +419,6 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
}
private async void HeartBeat(object? state = null) {
if (WebBrowser == null) {
throw new InvalidOperationException(nameof(WebBrowser));
}
if (!Bot.IsConnectedAndLoggedOn || (Bot.HeartBeatFailures > 0)) {
return;
}
@@ -420,6 +497,20 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
}
private async Task<bool?> IsEligibleForMatching() {
// Bot can't be limited
if (Bot.IsAccountLimited) {
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.IsAccountLimited)}: {Bot.IsAccountLimited}"));
return false;
}
// Bot can't be on lockdown
if (Bot.IsAccountLocked) {
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.IsAccountLocked)}: {Bot.IsAccountLocked}"));
return false;
}
// Bot must have ASF 2FA
if (!Bot.HasMobileAuthenticator) {
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.HasMobileAuthenticator)}: {Bot.HasMobileAuthenticator}"));
@@ -440,17 +531,22 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
if (hasValidApiKey != true) {
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.ArchiWebHandler.HasValidApiKey)}: {hasValidApiKey?.ToString() ?? "null"}"));
return hasValidApiKey;
return hasValidApiKey.HasValue ? false : null;
}
// Bot can't be trade banned
(bool _, bool? Result) economyBan = await Bot.ArchiWebHandler.CachedEconomyBan.GetValue(ECacheFallback.SuccessPreviously).ConfigureAwait(false);
if (economyBan.Result != false) {
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(economyBan)}: {economyBan.Result?.ToString() ?? "null"}"));
return economyBan.Result.HasValue ? false : null;
}
return true;
}
private async void MatchActively(object? state = null) {
if (WebBrowser == null) {
throw new InvalidOperationException(nameof(WebBrowser));
}
if (ASF.GlobalConfig == null) {
throw new InvalidOperationException(nameof(ASF.GlobalConfig));
}
@@ -487,6 +583,8 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
return;
}
bool tradesSent;
try {
Bot.ArchiLogger.LogGenericInfo(Strings.Starting);
@@ -513,9 +611,9 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
}
// Remove from our inventory items that can't be possibly matched due to no dupes to offer available
Dictionary<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity), List<uint>> inventorySets = Trading.GetInventorySets(ourInventory.Values);
HashSet<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity)> setsToKeep = Trading.GetInventorySets(ourInventory.Values).Where(static set => set.Value.Any(static amount => amount > 1)).Select(static set => set.Key).ToHashSet();
HashSet<ulong> assetIDsToRemove = ourInventory.Where(item => !inventorySets.TryGetValue((item.Value.RealAppID, item.Value.Type, item.Value.Rarity), out List<uint>? amounts) || (amounts.Count == 0) || amounts.All(static amount => amount < 2)).Select(static item => item.Key).ToHashSet();
HashSet<ulong> assetIDsToRemove = ourInventory.Where(item => !setsToKeep.Contains((item.Value.RealAppID, item.Value.Type, item.Value.Rarity))).Select(static item => item.Key).ToHashSet();
foreach (ulong assetIDToRemove in assetIDsToRemove) {
ourInventory.Remove(assetIDToRemove);
@@ -543,7 +641,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
}
if (response.Value.Users.IsEmpty) {
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(response.Value.Users)));
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(response.Value.Users)));
return;
}
@@ -552,16 +650,22 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
using (await Bot.Actions.GetTradingLock().ConfigureAwait(false)) {
#pragma warning restore CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose
Bot.ArchiLogger.LogGenericInfo(Strings.Starting);
await MatchActively(response.Value.Users, ourInventory, acceptedMatchableTypes).ConfigureAwait(false);
tradesSent = await MatchActively(response.Value.Users, ourInventory, acceptedMatchableTypes).ConfigureAwait(false);
}
Bot.ArchiLogger.LogGenericInfo(Strings.Done);
} finally {
MatchActivelySemaphore.Release();
}
if (tradesSent && ShouldSendHeartBeats && (DateTime.UtcNow > LastAnnouncement.AddMinutes(ShouldSendAnnouncementEarlier ? MinAnnouncementTTL : MaxAnnouncementTTL))) {
// If we're announced, it makes sense to update our state now, at least once
Bot.RequestPersonaStateUpdate();
}
}
private async Task MatchActively(IReadOnlyCollection<ListedUser> listedUsers, Dictionary<ulong, Asset> ourInventory, IReadOnlyCollection<Asset.EType> acceptedMatchableTypes) {
private async Task<bool> MatchActively(IReadOnlyCollection<ListedUser> listedUsers, Dictionary<ulong, Asset> ourInventory, IReadOnlyCollection<Asset.EType> acceptedMatchableTypes) {
if ((listedUsers == null) || (listedUsers.Count == 0)) {
throw new ArgumentNullException(nameof(listedUsers));
}
@@ -580,14 +684,67 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
// User doesn't have any more dupes in the inventory
Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, $"{nameof(ourFullState)} || {nameof(ourTradableState)}"));
return;
return false;
}
// Cancel previous trade offers sent and deprioritize SteamIDs that didn't answer us in this round
HashSet<ulong>? matchActivelyTradeOfferIDs = null;
JToken? matchActivelyTradeOfferIDsToken = Bot.BotDatabase.LoadFromJsonStorage(MatchActivelyTradeOfferIDsStorageKey);
if (matchActivelyTradeOfferIDsToken != null) {
try {
matchActivelyTradeOfferIDs = matchActivelyTradeOfferIDsToken.ToObject<HashSet<ulong>>();
} catch (Exception e) {
Bot.ArchiLogger.LogGenericWarningException(e);
}
}
matchActivelyTradeOfferIDs ??= new HashSet<ulong>();
HashSet<ulong> deprioritizedSteamIDs = new();
if (matchActivelyTradeOfferIDs.Count > 0) {
// This is not a mandatory step, we allow it to fail
HashSet<TradeOffer>? sentTradeOffers = await Bot.ArchiWebHandler.GetTradeOffers(true, false, true, false).ConfigureAwait(false);
if (sentTradeOffers != null) {
HashSet<ulong> activeTradeOfferIDs = new();
foreach (TradeOffer tradeOffer in sentTradeOffers.Where(tradeOffer => (tradeOffer.State == ETradeOfferState.Active) && matchActivelyTradeOfferIDs.Contains(tradeOffer.TradeOfferID))) {
deprioritizedSteamIDs.Add(tradeOffer.OtherSteamID64);
if (!await Bot.ArchiWebHandler.CancelTradeOffer(tradeOffer.TradeOfferID).ConfigureAwait(false)) {
activeTradeOfferIDs.Add(tradeOffer.TradeOfferID);
}
}
if (!matchActivelyTradeOfferIDs.SetEquals(activeTradeOfferIDs)) {
matchActivelyTradeOfferIDs = activeTradeOfferIDs;
if (matchActivelyTradeOfferIDs.Count > 0) {
Bot.BotDatabase.SaveToJsonStorage(MatchActivelyTradeOfferIDsStorageKey, JToken.FromObject(matchActivelyTradeOfferIDs));
} else {
Bot.BotDatabase.DeleteFromJsonStorage(MatchActivelyTradeOfferIDsStorageKey);
}
}
}
}
HashSet<ulong> pendingMobileTradeOfferIDs = new();
byte maxTradeHoldDuration = ASF.GlobalConfig?.MaxTradeHoldDuration ?? GlobalConfig.DefaultMaxTradeHoldDuration;
byte failuresInRow = 0;
uint matchedSets = 0;
foreach (ListedUser listedUser in listedUsers.Where(listedUser => (listedUser.SteamID != Bot.SteamID) && acceptedMatchableTypes.Any(listedUser.MatchableTypes.Contains) && !Bot.IsBlacklistedFromTrades(listedUser.SteamID)).OrderByDescending(static listedUser => listedUser.MatchEverything).ThenBy(static listedUser => listedUser.Assets.Count)) {
foreach (ListedUser listedUser in listedUsers.Where(listedUser => (listedUser.SteamID != Bot.SteamID) && acceptedMatchableTypes.Any(listedUser.MatchableTypes.Contains) && !Bot.IsBlacklistedFromTrades(listedUser.SteamID)).OrderBy(listedUser => deprioritizedSteamIDs.Contains(listedUser.SteamID)).ThenByDescending(static listedUser => listedUser.MatchEverything).ThenBy(static listedUser => listedUser.TotalInventoryCount)) {
if (failuresInRow >= WebBrowser.MaxTries) {
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(failuresInRow)} >= {WebBrowser.MaxTries}"));
break;
}
HashSet<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity)> wantedSets = ourTradableState.Keys.Where(set => listedUser.MatchableTypes.Contains(set.Type)).ToHashSet();
if (wantedSets.Count == 0) {
@@ -750,33 +907,46 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
if ((itemsToGive.Count != itemsToReceive.Count) || !Trading.IsFairExchange(itemsToGive, itemsToReceive)) {
// Failsafe
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, Strings.ErrorAborted));
return;
throw new InvalidOperationException($"{nameof(itemsToGive)} && {nameof(itemsToReceive)}");
}
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Localization.Strings.MatchingFound, itemsToReceive.Count, listedUser.SteamID, listedUser.Nickname));
Bot.ArchiLogger.LogGenericTrace($"{Bot.SteamID} <- {string.Join(", ", itemsToReceive.Select(static item => $"{item.RealAppID}/{item.Type}/{item.Rarity}/{item.ClassID} #{item.Amount}"))} | {string.Join(", ", itemsToGive.Select(static item => $"{item.RealAppID}/{item.Type}/{item.Rarity}/{item.ClassID} #{item.Amount}"))} -> {listedUser.SteamID}");
(bool success, HashSet<ulong>? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(listedUser.SteamID, itemsToGive, itemsToReceive, listedUser.TradeToken, true).ConfigureAwait(false);
(bool success, HashSet<ulong>? tradeOfferIDs, HashSet<ulong>? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(listedUser.SteamID, itemsToGive, itemsToReceive, listedUser.TradeToken, true).ConfigureAwait(false);
if ((mobileTradeOfferIDs?.Count > 0) && Bot.HasMobileAuthenticator) {
(bool twoFactorSuccess, _, _) = await Bot.Actions.HandleTwoFactorAuthenticationConfirmations(true, Confirmation.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false);
if (tradeOfferIDs?.Count > 0) {
matchActivelyTradeOfferIDs.UnionWith(tradeOfferIDs);
if (!twoFactorSuccess) {
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(twoFactorSuccess)));
Bot.BotDatabase.SaveToJsonStorage(MatchActivelyTradeOfferIDsStorageKey, JToken.FromObject(matchActivelyTradeOfferIDs));
}
return;
if (mobileTradeOfferIDs?.Count > 0) {
pendingMobileTradeOfferIDs.UnionWith(mobileTradeOfferIDs);
if (pendingMobileTradeOfferIDs.Count >= MaxTradeOffersActive) {
(bool twoFactorSuccess, IReadOnlyCollection<Confirmation>? handledConfirmations, _) = await Bot.Actions.HandleTwoFactorAuthenticationConfirmations(true, Confirmation.EType.Trade, pendingMobileTradeOfferIDs, true).ConfigureAwait(false);
if (!twoFactorSuccess) {
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ActivelyMatchingSomeConfirmationsFailed, handledConfirmations?.Count ?? 0, pendingMobileTradeOfferIDs.Count));
}
pendingMobileTradeOfferIDs.Clear();
}
}
if (!success) {
// The user likely no longer has the items we need, this is fine, we can continue the matching with other ones
failuresInRow++;
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Localization.Strings.TradeOfferFailed, listedUser.SteamID, listedUser.Nickname));
break;
}
failuresInRow = 0;
Bot.ArchiLogger.LogGenericInfo(Strings.Success);
// Assume the trade offer has went through and was accepted, this will allow us to keep matching the same set with different users as if we've got what we wanted
@@ -851,6 +1021,16 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
}
}
if (pendingMobileTradeOfferIDs.Count > 0) {
(bool twoFactorSuccess, IReadOnlyCollection<Confirmation>? handledConfirmations, _) = await Bot.Actions.HandleTwoFactorAuthenticationConfirmations(true, Confirmation.EType.Trade, pendingMobileTradeOfferIDs, true).ConfigureAwait(false);
if (!twoFactorSuccess) {
Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ActivelyMatchingSomeConfirmationsFailed, handledConfirmations?.Count ?? 0, pendingMobileTradeOfferIDs.Count));
}
}
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Localization.Strings.ActivelyMatchingItemsRound, matchedSets));
return matchedSets > 0;
}
}

View File

@@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ConfigureAwaitChecker.Analyzer" PrivateAssets="all" />
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="Newtonsoft.Json" IncludeAssets="compile" />
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net481' OR '$(TargetFramework)' == 'netstandard2.1'">
<!-- Madness is already included in netf build of ASF, so we don't need to emit it ourselves -->
<PackageReference Update="JustArchiNET.Madness" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ArchiSteamFarm\ArchiSteamFarm.csproj" ExcludeAssets="all" Private="false" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Localization\Strings.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Update="Localization\Strings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Strings.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,24 @@
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// |
// http://www.apache.org/licenses/LICENSE-2.0
// |
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
[assembly: CLSCompliant(false)]

View File

@@ -0,0 +1,414 @@
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// |
// http://www.apache.org/licenses/LICENSE-2.0
// |
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using ArchiSteamFarm.Core;
using ArchiSteamFarm.Localization;
using ArchiSteamFarm.Steam;
using Newtonsoft.Json;
using SteamKit2;
using SteamKit2.Internal;
namespace ArchiSteamFarm.OfficialPlugins.MobileAuthenticator;
internal static class Commands {
private const byte MaxFinalizationAttempts = 900 / Steam.Security.MobileAuthenticator.CodeInterval;
internal static async Task<string?> OnBotCommand(Bot bot, EAccess access, string message, string[] args, ulong steamID = 0) {
ArgumentNullException.ThrowIfNull(bot);
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
if (string.IsNullOrEmpty(message)) {
throw new ArgumentNullException(nameof(message));
}
if ((args == null) || (args.Length == 0)) {
throw new ArgumentNullException(nameof(args));
}
if ((steamID != 0) && !new SteamID(steamID).IsIndividualAccount) {
throw new ArgumentOutOfRangeException(nameof(steamID));
}
switch (args.Length) {
case 1:
switch (args[0].ToUpperInvariant()) {
case "2FAFINALIZEDFORCE":
return await ResponseTwoFactorFinalized(access, bot).ConfigureAwait(false);
case "2FAINIT":
return await ResponseTwoFactorInit(access, bot).ConfigureAwait(false);
}
break;
default:
switch (args[0].ToUpperInvariant()) {
case "2FAFINALIZE" when args.Length > 2:
return await ResponseTwoFactorFinalize(access, args[1], Utilities.GetArgsAsText(message, 2), steamID).ConfigureAwait(false);
case "2FAFINALIZE":
return await ResponseTwoFactorFinalize(access, bot, args[1]).ConfigureAwait(false);
case "2FAFINALIZED" when args.Length > 2:
return await ResponseTwoFactorFinalized(access, args[1], Utilities.GetArgsAsText(message, 2), steamID).ConfigureAwait(false);
case "2FAFINALIZED":
return await ResponseTwoFactorFinalized(access, bot, args[1]).ConfigureAwait(false);
case "2FAFINALIZEDFORCE":
return await ResponseTwoFactorFinalized(access, Utilities.GetArgsAsText(args, 1, ","), steamID: steamID).ConfigureAwait(false);
case "2FAINIT":
return await ResponseTwoFactorInit(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false);
}
break;
}
return null;
}
private static async Task<string?> ResponseTwoFactorFinalize(EAccess access, Bot bot, string activationCode) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
ArgumentNullException.ThrowIfNull(bot);
if (string.IsNullOrEmpty(activationCode)) {
throw new ArgumentNullException(nameof(activationCode));
}
if (access < EAccess.Master) {
return access > EAccess.None ? bot.Commands.FormatBotResponse(Strings.ErrorAccessDenied) : null;
}
if (bot.HasMobileAuthenticator) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(bot.HasMobileAuthenticator)));
}
if (!bot.IsConnectedAndLoggedOn) {
return bot.Commands.FormatBotResponse(Strings.BotNotConnected);
}
string maFilePath = bot.GetFilePath(Bot.EFileType.MobileAuthenticator);
string maFilePendingPath = $"{maFilePath}.PENDING";
if (!File.Exists(maFilePendingPath)) {
return bot.Commands.FormatBotResponse(Strings.NothingFound);
}
string json;
try {
json = await File.ReadAllTextAsync(maFilePendingPath).ConfigureAwait(false);
} catch (Exception e) {
bot.ArchiLogger.LogGenericException(e);
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message));
}
if (string.IsNullOrEmpty(json)) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
}
Steam.Security.MobileAuthenticator? mobileAuthenticator = JsonConvert.DeserializeObject<Steam.Security.MobileAuthenticator>(json);
if (mobileAuthenticator == null) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
}
mobileAuthenticator.Init(bot);
MobileAuthenticatorHandler? mobileAuthenticatorHandler = bot.GetHandler<MobileAuthenticatorHandler>();
if (mobileAuthenticatorHandler == null) {
throw new InvalidOperationException(nameof(mobileAuthenticatorHandler));
}
ulong steamTime = await mobileAuthenticator.GetSteamTime().ConfigureAwait(false);
bool successFinalizing = false;
for (byte i = 0; i < MaxFinalizationAttempts; i++) {
if (i > 0) {
steamTime += Steam.Security.MobileAuthenticator.CodeInterval;
}
string? code = mobileAuthenticator.GenerateTokenForTime(steamTime);
if (string.IsNullOrEmpty(code)) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(mobileAuthenticator.GenerateTokenForTime)));
}
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
CTwoFactor_FinalizeAddAuthenticator_Response? response = await mobileAuthenticatorHandler.FinalizeAuthenticator(bot.SteamID, activationCode, code!, steamTime).ConfigureAwait(false);
if (response == null) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(mobileAuthenticatorHandler.FinalizeAuthenticator)));
}
if (response.want_more) {
// OK, whatever
continue;
}
if (!response.success) {
EResult result = (EResult) response.status;
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, result));
}
successFinalizing = true;
break;
}
if (!successFinalizing) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorRequestFailedTooManyTimes, MaxFinalizationAttempts));
}
if (!bot.TryImportAuthenticator(mobileAuthenticator)) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(bot.TryImportAuthenticator)));
}
string maFileFinishedPath = $"{maFilePath}.NEW";
try {
File.Move(maFilePendingPath, maFileFinishedPath, true);
} catch (Exception e) {
bot.ArchiLogger.LogGenericException(e);
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message));
}
return bot.Commands.FormatBotResponse(Strings.Done);
}
private static async Task<string?> ResponseTwoFactorFinalize(EAccess access, string botNames, string activationCode, ulong steamID = 0) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
if (string.IsNullOrEmpty(botNames)) {
throw new ArgumentNullException(nameof(botNames));
}
if (string.IsNullOrEmpty(activationCode)) {
throw new ArgumentNullException(nameof(activationCode));
}
if ((steamID != 0) && !new SteamID(steamID).IsIndividualAccount) {
throw new ArgumentOutOfRangeException(nameof(steamID));
}
HashSet<Bot>? bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return access >= EAccess.Owner ? Steam.Interaction.Commands.FormatStaticResponse(string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botNames)) : null;
}
IList<string?> results = await Utilities.InParallel(bots.Select(bot => ResponseTwoFactorFinalize(Steam.Interaction.Commands.GetProxyAccess(bot, access, steamID), bot, activationCode))).ConfigureAwait(false);
List<string> responses = new(results.Where(static result => !string.IsNullOrEmpty(result))!);
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}
private static async Task<string?> ResponseTwoFactorFinalized(EAccess access, Bot bot, string? activationCode = null) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
ArgumentNullException.ThrowIfNull(bot);
if (access < EAccess.Master) {
return access > EAccess.None ? bot.Commands.FormatBotResponse(Strings.ErrorAccessDenied) : null;
}
if (bot.HasMobileAuthenticator) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(bot.HasMobileAuthenticator)));
}
string maFilePath = bot.GetFilePath(Bot.EFileType.MobileAuthenticator);
string maFilePendingPath = $"{maFilePath}.PENDING";
if (!File.Exists(maFilePendingPath)) {
return bot.Commands.FormatBotResponse(Strings.NothingFound);
}
string json;
try {
json = await File.ReadAllTextAsync(maFilePendingPath).ConfigureAwait(false);
} catch (Exception e) {
bot.ArchiLogger.LogGenericException(e);
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message));
}
if (string.IsNullOrEmpty(json)) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
}
Steam.Security.MobileAuthenticator? mobileAuthenticator = JsonConvert.DeserializeObject<Steam.Security.MobileAuthenticator>(json);
if (mobileAuthenticator == null) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(json)));
}
mobileAuthenticator.Init(bot);
if (!string.IsNullOrEmpty(activationCode)) {
string? generatedCode = await mobileAuthenticator.GenerateToken().ConfigureAwait(false);
if (generatedCode != activationCode) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{generatedCode} != {activationCode}"));
}
}
if (!bot.TryImportAuthenticator(mobileAuthenticator)) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(bot.TryImportAuthenticator)));
}
string maFileFinishedPath = $"{maFilePath}.NEW";
try {
File.Move(maFilePendingPath, maFileFinishedPath, true);
} catch (Exception e) {
bot.ArchiLogger.LogGenericException(e);
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message));
}
return bot.Commands.FormatBotResponse(Strings.Done);
}
private static async Task<string?> ResponseTwoFactorFinalized(EAccess access, string botNames, string? activationCode = null, ulong steamID = 0) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
if (string.IsNullOrEmpty(botNames)) {
throw new ArgumentNullException(nameof(botNames));
}
if ((steamID != 0) && !new SteamID(steamID).IsIndividualAccount) {
throw new ArgumentOutOfRangeException(nameof(steamID));
}
HashSet<Bot>? bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return access >= EAccess.Owner ? Steam.Interaction.Commands.FormatStaticResponse(string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botNames)) : null;
}
IList<string?> results = await Utilities.InParallel(bots.Select(bot => ResponseTwoFactorFinalized(Steam.Interaction.Commands.GetProxyAccess(bot, access, steamID), bot, activationCode))).ConfigureAwait(false);
List<string> responses = new(results.Where(static result => !string.IsNullOrEmpty(result))!);
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}
private static async Task<string?> ResponseTwoFactorInit(EAccess access, Bot bot) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
ArgumentNullException.ThrowIfNull(bot);
if (access < EAccess.Master) {
return access > EAccess.None ? bot.Commands.FormatBotResponse(Strings.ErrorAccessDenied) : null;
}
if (bot.HasMobileAuthenticator) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(bot.HasMobileAuthenticator)));
}
if (!bot.IsConnectedAndLoggedOn) {
return bot.Commands.FormatBotResponse(Strings.BotNotConnected);
}
MobileAuthenticatorHandler? mobileAuthenticatorHandler = bot.GetHandler<MobileAuthenticatorHandler>();
if (mobileAuthenticatorHandler == null) {
throw new InvalidOperationException(nameof(mobileAuthenticatorHandler));
}
string deviceID = $"android:{Guid.NewGuid()}";
CTwoFactor_AddAuthenticator_Response? response = await mobileAuthenticatorHandler.AddAuthenticator(bot.SteamID, deviceID).ConfigureAwait(false);
if (response == null) {
return bot.Commands.FormatBotResponse(Strings.WarningFailed);
}
EResult result = (EResult) response.status;
if (result != EResult.OK) {
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, result));
}
MaFileData maFileData = new(response, deviceID);
string maFilePendingPath = $"{bot.GetFilePath(Bot.EFileType.MobileAuthenticator)}.PENDING";
string json = JsonConvert.SerializeObject(maFileData, Formatting.Indented);
try {
await File.WriteAllTextAsync(maFilePendingPath, json).ConfigureAwait(false);
} catch (Exception e) {
bot.ArchiLogger.LogGenericException(e);
return bot.Commands.FormatBotResponse(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, e.Message));
}
return bot.Commands.FormatBotResponse(Strings.Done);
}
private static async Task<string?> ResponseTwoFactorInit(EAccess access, string botNames, ulong steamID = 0) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
if (string.IsNullOrEmpty(botNames)) {
throw new ArgumentNullException(nameof(botNames));
}
if ((steamID != 0) && !new SteamID(steamID).IsIndividualAccount) {
throw new ArgumentOutOfRangeException(nameof(steamID));
}
HashSet<Bot>? bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return access >= EAccess.Owner ? Steam.Interaction.Commands.FormatStaticResponse(string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botNames)) : null;
}
IList<string?> results = await Utilities.InParallel(bots.Select(bot => ResponseTwoFactorInit(Steam.Interaction.Commands.GetProxyAccess(bot, access, steamID), bot))).ConfigureAwait(false);
List<string> responses = new(results.Where(static result => !string.IsNullOrEmpty(result))!);
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}
}

View File

@@ -0,0 +1,3 @@
This directory contains ASF strings for display and localization purposes.
All strings used by ASF can be found in main `Strings.resx` file, and that's also the only `resx` file that should be modified - all other `resx` files are managed automatically and should not be touched. Please visit **[localization](https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Localization)** section on the wiki if you want to improve translation of other files.

View File

@@ -0,0 +1,48 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ArchiSteamFarm.OfficialPlugins.MobileAuthenticator.Localization {
using System;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Strings {
private static System.Resources.ResourceManager resourceMan;
private static System.Globalization.CultureInfo resourceCulture;
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Strings() {
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Resources.ResourceManager ResourceManager {
get {
if (object.Equals(null, resourceMan)) {
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("ArchiSteamFarm.OfficialPlugins.MobileAuthenticator.Localization.Strings", typeof(Strings).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root" xmlns="">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="" id="root">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
</root>

View File

@@ -0,0 +1,81 @@
// _ _ _ ____ _ _____
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
// |
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
// Contact: JustArchi@JustArchi.net
// |
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// |
// http://www.apache.org/licenses/LICENSE-2.0
// |
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using Newtonsoft.Json;
using SteamKit2.Internal;
namespace ArchiSteamFarm.OfficialPlugins.MobileAuthenticator;
internal sealed class MaFileData {
[JsonProperty("account_name", Required = Required.Always)]
internal readonly string AccountName;
[JsonProperty("device_id", Required = Required.Always)]
internal readonly string DeviceID;
[JsonProperty("identity_secret", Required = Required.Always)]
internal readonly string IdentitySecret;
[JsonProperty("revocation_code", Required = Required.Always)]
internal readonly string RevocationCode;
[JsonProperty("secret_1", Required = Required.Always)]
internal readonly string Secret1;
[JsonProperty("serial_number", Required = Required.Always)]
internal readonly ulong SerialNumber;
[JsonProperty("server_time", Required = Required.Always)]
internal readonly ulong ServerTime;
[JsonProperty("shared_secret", Required = Required.Always)]
internal readonly string SharedSecret;
[JsonProperty("status", Required = Required.Always)]
internal readonly int Status;
[JsonProperty("token_gid", Required = Required.Always)]
internal readonly string TokenGid;
[JsonProperty("uri", Required = Required.Always)]
internal readonly string Uri;
internal MaFileData(CTwoFactor_AddAuthenticator_Response data, string deviceID) {
ArgumentNullException.ThrowIfNull(data);
if (string.IsNullOrEmpty(deviceID)) {
throw new ArgumentNullException(nameof(deviceID));
}
AccountName = data.account_name;
DeviceID = deviceID;
IdentitySecret = Convert.ToBase64String(data.identity_secret);
RevocationCode = data.revocation_code;
Secret1 = Convert.ToBase64String(data.secret_1);
SerialNumber = data.serial_number;
ServerTime = data.server_time;
SharedSecret = Convert.ToBase64String(data.shared_secret);
Status = data.status;
TokenGid = data.token_gid;
Uri = data.uri;
}
}

Some files were not shown because too many files have changed in this diff Show More