From 6d8c7eac46289f4f53cac526276e8ed3b7f8c942 Mon Sep 17 00:00:00 2001 From: Deyan Nenov Date: Wed, 29 Nov 2023 13:48:16 +0000 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f5d55636f77605bc6e1f818f08fb367c43a87da5 Author: Deyan Nenov Date: Tue Nov 28 12:12:19 2023 +0000 dispose methods null checks - trying to prevent null exceptions in case resources have been cleared before dispose event has been called commit e43ad538f0a6c6416d3a9204a81311a99bbb23f0 Author: Deyan Nenov Date: Tue Nov 28 11:05:20 2023 +0000 remove begin invoke from mainFrame_Navigated - this was done to try and fix a failing test but it should not be needed commit 42bf04c0df4d52925cdecefc93a42a7565f909de Author: Deyan Nenov Date: Mon Nov 27 21:04:19 2023 +0000 null check to mainFrame_Navigated - added a null check commit 9dde030c5d565baf203f25794724dfa8eb51d91b Merge: a77a11a877 3f765b51ad Author: Deyan Nenov Date: Mon Nov 27 18:07:39 2023 +0000 Merge branch 'pm-publishpackage-cherrypick-resources' into pm-publishpackage-cherrypick-mypackage commit a77a11a8774c8c1f98f26e679905b492c691620f Author: Deyan Nenov Date: Mon Nov 27 17:47:17 2023 +0000 main changes - this cherry-pick contains all main changes minus resources and tests. - will need to merge resources to work correctly - if this breaks the test run, we will need to further split it up, or introduce the changes one by one somehow commit 3f765b51ad31c80e9c1f77d457310b32717ff4d0 Merge: 95d502a95b 36fb8d31b3 Author: Deyan Nenov Date: Mon Nov 27 17:38:11 2023 +0000 Merge remote-tracking branch 'upstream/master' into pm-publishpackage-cherrypick-resources commit 95d502a95b5437e809865b7170495c8007703055 Author: Deyan Nenov Date: Mon Nov 27 17:38:02 2023 +0000 resource cherry-pick - picked up all resource changes commit 36fb8d31b3fc60fcea57354d81d8a9ce070d6149 Author: Jorgen Dahl Date: Mon Nov 27 11:51:35 2023 -0500 Test net8 (#14635) * Test net8 * Also add DotNet to the build properties * Update CS_SDK.props * Update CS_SDK.props * update * update * update * Go back to net6 --------- Co-authored-by: pinzart commit cbba6d073ded1a4cfaf8a323401f5b80eae1b585 Author: Michael Kirschner Date: Mon Nov 27 11:26:04 2023 -0500 DYN-6412 fix performance issue with feature flags, and deadlock with CLI wrapper. (#14637) * fix for null data being shown over and over * fix issues with cli wrapper get data * revert * add test * review comments add tests * comments * review comments commit c5df6f9ab3ef5ad73a55cea82d422b8c1941ca9a Author: Ashish Aggarwal Date: Mon Nov 27 11:22:32 2023 -0500 Replace Application.Current with HostAnalyticsInfo.HostName check (#14574) * Fix PostDiff job * replace application.current * tests * refactor after Bogdans PR --------- Co-authored-by: Aaron (Qilong) <173288704@qq.com> commit 11b1f7c30546308e273a027c11a84936a005dd2d Author: jesusalvino <96534278+jesusalvino@users.noreply.github.com> Date: Mon Nov 27 08:55:32 2023 -0500 DYN-6313 Add ML Node AutoComplete TOU (#14625) * Updating the Agreement and Term of Use * Adding the MLNodeAuntocomplete rtf file * Persists the AgreeToMLAutocompleteTOU as preference settings * rename property * resources and control names * Clean up * Update * update --------- Co-authored-by: Jesus Alfredo Alviño Co-authored-by: Aaron (Qilong) commit 3e97cbdc8a5e6e47a7c480febd17ed1e4d047ad1 Author: Aabishkar KC Date: Wed Nov 22 12:56:04 2023 -0500 Update smoke tests workflow (#14638) --- .github/workflows/ui_smoke_tests.yml | 3 +- doc/distrib/MLNodeAutocompleteConsent.rtf | 195 ++++++++++++++++++ src/Config/CS_SDK.props | 8 +- .../Configuration/PreferenceSettings.cs | 17 ++ src/DynamoCore/DynamoCore.csproj | 1 + src/DynamoCore/Models/DynamoModel.cs | 2 +- .../Controls/InPortContextMenu.xaml.cs | 11 +- .../Controls/IncanvasSearchControl.xaml.cs | 5 +- .../NodeAutoCompleteSearchControl.xaml.cs | 8 +- .../Controls/OutPortContextMenu.xaml.cs | 8 +- .../Properties/Resources.Designer.cs | 15 +- .../Properties/Resources.en-US.resx | 11 +- src/DynamoCoreWpf/Properties/Resources.resx | 13 +- .../Services/UsageReportingManager.cs | 5 +- .../UsageReportingAgreementPrompt.xaml | 44 +++- .../UsageReportingAgreementPrompt.xaml.cs | 22 +- .../PackageManagerSearchViewModel.cs | 1 + .../PackageManager/PackageManagerViewModel.cs | 2 + .../PackageManager/PublishPackageViewModel.cs | 30 ++- .../ViewModels/RunSettingsViewModel.cs | 4 +- .../ViewModels/Search/BrowserItemViewModel.cs | 36 +++- .../Views/Core/DynamoView.xaml.cs | 10 +- .../PackageManagerPublishControl.xaml.cs | 42 ++-- .../PackageManager/PackageManagerView.xaml.cs | 6 +- .../Pages/PublishPackagePreviewPage.xaml.cs | 2 +- .../Pages/PublishPackagePublishPage.xaml.cs | 2 +- .../Pages/PublishPackageSelectPage.xaml.cs | 4 +- src/DynamoPackages/PackageDirectoryBuilder.cs | 4 +- src/DynamoPackages/PackageUploadBuilder.cs | 1 - src/DynamoUtilities/CLIWrapper.cs | 175 ++++++++++++++++ .../DynamoFeatureFlagsManager.cs | 57 +++-- src/DynamoUtilities/Md2Html.cs | 171 +-------------- .../Properties/AssemblyInfo.cs | 2 + src/build.xml | 2 +- test/Directory.Build.props | 5 + .../Logging/FeatureFlagTests.cs | 38 ++++ .../PackageManagerViewExtensionTests.cs | 2 +- .../DynamoUtilitiesTests/CLIWrapperTests.cs | 58 ++++++ test/settings/DynamoSettings-NewSettings.xml | 1 + 39 files changed, 737 insertions(+), 286 deletions(-) create mode 100644 doc/distrib/MLNodeAutocompleteConsent.rtf create mode 100644 src/DynamoUtilities/CLIWrapper.cs create mode 100644 test/Directory.Build.props create mode 100644 test/Libraries/DynamoUtilitiesTests/CLIWrapperTests.cs diff --git a/.github/workflows/ui_smoke_tests.yml b/.github/workflows/ui_smoke_tests.yml index 737773854ce..e32e5dbf793 100644 --- a/.github/workflows/ui_smoke_tests.yml +++ b/.github/workflows/ui_smoke_tests.yml @@ -11,7 +11,6 @@ env: TEST_EXECUTE_DOWNLOAD_URL: https://downloads.smartbear.com/TestExecute1552SLM.exe ACTOR: ${{ github.actor }} WORKFLOW_ID: ${{ github.event.workflow_run.workflow_id }} - WORKFLOW_CONCLUSION: ${{ github.event.workflow_run.conclusion }} RUN_ID: ${{ github.event.workflow_run.id }} RUN_NAME: ${{ github.event.workflow_run.name }} RUN_URL: ${{ github.event.workflow_run.html_url }} @@ -21,7 +20,7 @@ jobs: name: UI Smoke Tests timeout-minutes: 60 runs-on: windows-latest - if: ${{ env.WORKFLOW_CONCLUSION == 'success' }} + if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - name: Checkout uses: actions/checkout@v4 diff --git a/doc/distrib/MLNodeAutocompleteConsent.rtf b/doc/distrib/MLNodeAutocompleteConsent.rtf new file mode 100644 index 00000000000..4269ec83948 --- /dev/null +++ b/doc/distrib/MLNodeAutocompleteConsent.rtf @@ -0,0 +1,195 @@ +{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff37\deff0\stshfdbch0\stshfloch37\stshfhich37\stshfbi37\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\f11\fbidi \fmodern\fcharset128\fprq1{\*\panose 02020609040205080304}MS Mincho{\*\falt ?l?r ??\'81\'66c};}{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;} +{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\f40\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0604030504040204}Verdana;}{\f43\fbidi \fmodern\fcharset128\fprq1{\*\panose 00000000000000000000}@MS Mincho;} +{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\fhimajor\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;}{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f45\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} +{\f46\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f48\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f49\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f50\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\f51\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f52\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f53\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} +{\f157\fbidi \fmodern\fcharset0\fprq1 MS Mincho Western{\*\falt ?l?r ??\'81\'66c};}{\f155\fbidi \fmodern\fcharset238\fprq1 MS Mincho CE{\*\falt ?l?r ??\'81\'66c};}{\f156\fbidi \fmodern\fcharset204\fprq1 MS Mincho Cyr{\*\falt ?l?r ??\'81\'66c};} +{\f158\fbidi \fmodern\fcharset161\fprq1 MS Mincho Greek{\*\falt ?l?r ??\'81\'66c};}{\f159\fbidi \fmodern\fcharset162\fprq1 MS Mincho Tur{\*\falt ?l?r ??\'81\'66c};}{\f162\fbidi \fmodern\fcharset186\fprq1 MS Mincho Baltic{\*\falt ?l?r ??\'81\'66c};} +{\f385\fbidi \froman\fcharset238\fprq2 Cambria Math CE;}{\f386\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;}{\f388\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}{\f389\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;} +{\f392\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;}{\f393\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);}{\f415\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f416\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;} +{\f418\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f419\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f420\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\f421\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);} +{\f422\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f423\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\f445\fbidi \fswiss\fcharset238\fprq2 Verdana CE;}{\f446\fbidi \fswiss\fcharset204\fprq2 Verdana Cyr;} +{\f448\fbidi \fswiss\fcharset161\fprq2 Verdana Greek;}{\f449\fbidi \fswiss\fcharset162\fprq2 Verdana Tur;}{\f452\fbidi \fswiss\fcharset186\fprq2 Verdana Baltic;}{\f453\fbidi \fswiss\fcharset163\fprq2 Verdana (Vietnamese);} +{\f477\fbidi \fmodern\fcharset0\fprq1 @MS Mincho Western;}{\f475\fbidi \fmodern\fcharset238\fprq1 @MS Mincho CE;}{\f476\fbidi \fmodern\fcharset204\fprq1 @MS Mincho Cyr;}{\f478\fbidi \fmodern\fcharset161\fprq1 @MS Mincho Greek;} +{\f479\fbidi \fmodern\fcharset162\fprq1 @MS Mincho Tur;}{\f482\fbidi \fmodern\fcharset186\fprq1 @MS Mincho Baltic;}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} +{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} +{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} +{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} +{\fhimajor\f31528\fbidi \froman\fcharset238\fprq2 Cambria CE;}{\fhimajor\f31529\fbidi \froman\fcharset204\fprq2 Cambria Cyr;}{\fhimajor\f31531\fbidi \froman\fcharset161\fprq2 Cambria Greek;}{\fhimajor\f31532\fbidi \froman\fcharset162\fprq2 Cambria Tur;} +{\fhimajor\f31535\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\fhimajor\f31536\fbidi \froman\fcharset163\fprq2 Cambria (Vietnamese);}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} +{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} +{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} +{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} +{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;} +{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} +{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;} +{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;} +{\fhiminor\f31573\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\fhiminor\f31574\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;} +{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}} +{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0; +\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red0\green0\blue0;\red0\green0\blue0;\red72\green148\blue208;\cbackgroundone\ctint255\cshade191\red191\green191\blue191;}{\*\defchp +\f37\fs22\cf19 }{\*\defpap \ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af37\afs22\alang1025 +\ltrch\fcs0 \f37\fs22\cf19\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 \sqformat \spriority0 \styrsid9534305 Normal;}{\s1\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\outlinelevel0\rin0\lin0\itap0 \rtlch\fcs1 \ab\af0\afs32\alang1025 +\ltrch\fcs0 \b\fs32\cf19\lang1033\langfe1033\kerning32\loch\f31502\hich\af31502\dbch\af31501\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink15 \sqformat \spriority9 \styrsid7559448 heading 1;}{ +\s2\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\outlinelevel1\rin0\lin0\itap0 \rtlch\fcs1 \ab\ai\af0\afs28\alang1025 \ltrch\fcs0 \b\i\fs28\cf19\lang1033\langfe1033\loch\f31502\hich\af31502\dbch\af31501\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext0 \slink16 \sqformat \spriority9 \styrsid7559448 heading 2;}{\s3\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\outlinelevel2\rin0\lin0\itap0 \rtlch\fcs1 \ab\af0\afs26\alang1025 \ltrch\fcs0 +\b\fs26\cf19\lang1033\langfe1033\loch\f31502\hich\af31502\dbch\af31501\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink17 \sqformat \spriority9 \styrsid7559448 heading 3;}{\*\cs10 \additive \sunhideused \spriority1 Default Paragraph Font;}{\* +\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa200\sl276\slmult1 +\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af37\afs22\alang1025 \ltrch\fcs0 \f37\fs22\cf19\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext11 \ssemihidden \sunhideused Normal Table;}{\*\cs15 \additive +\rtlch\fcs1 \ab\af0\afs32 \ltrch\fcs0 \b\fs32\kerning32\loch\f31502\hich\af31502\dbch\af31501 \sbasedon10 \slink1 \slocked \spriority9 \styrsid7559448 Heading 1 Char;}{\*\cs16 \additive \rtlch\fcs1 \ab\ai\af0\afs28 \ltrch\fcs0 +\b\i\fs28\loch\f31502\hich\af31502\dbch\af31501 \sbasedon10 \slink2 \slocked \spriority9 \styrsid7559448 Heading 2 Char;}{\*\cs17 \additive \rtlch\fcs1 \ab\af0\afs26 \ltrch\fcs0 \b\fs26\loch\f31502\hich\af31502\dbch\af31501 +\sbasedon10 \slink3 \slocked \spriority9 \styrsid7559448 Heading 3 Char;}}{\*\pgptbl {\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}{\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}}{\*\rsidtbl \rsid483671\rsid3037294\rsid5012088\rsid5136836\rsid5309285\rsid5378609\rsid6827092 +\rsid6963270\rsid7174336\rsid7559448\rsid9534305\rsid10551617\rsid12388035\rsid14363366\rsid14811469\rsid14831659\rsid15021189\rsid15617602\rsid16192969}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1 +\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\author Limiardi Sancerio}{\operator Jesus Alfredo Alvi\'f1o}{\creatim\yr2015\mo5\dy4\hr12\min55}{\revtim\yr2023\mo11\dy17\hr16\min18}{\version16}{\edmins11}{\nofpages1}{\nofwords57}{\nofchars331} +{\*\company Autodesk, Inc.}{\nofcharsws387}{\vern79}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect +\widowctrl\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors1\noxlattoyen +\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1440\dgvorigin1440\dghshow1\dgvshow1 +\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct +\asianbrkrule\rsidroot9534305\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0 +{\*\wgrffmtfilter 2450}\nofeaturethrottle1\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang +{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang +{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}} +\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\rin0\lin0\itap0\pararsid9534305 \rtlch\fcs1 \af37\afs22\alang1025 \ltrch\fcs0 \f37\fs22\cf19\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0\afs20 \ltrch\fcs0 +\b\fs20\cf20\lang1033\langfe1041\loch\af40\hich\af40\dbch\af11\langfenp1041\insrsid15021189\charrsid15021189 \hich\af40\dbch\af11\loch\f40 [}{\rtlch\fcs1 \af0\afs20 \ltrch\fcs0 +\b\fs20\cf20\lang1033\langfe1041\loch\af40\hich\af40\dbch\af11\langfenp1041\insrsid6963270 \hich\af40\dbch\af11\loch\f40 ML Node Autocomplete}{\rtlch\fcs1 \af0\afs20 \ltrch\fcs0 +\b\fs20\cf20\lang1033\langfe1041\loch\af40\hich\af40\dbch\af11\langfenp1041\insrsid15021189\charrsid15021189 \hich\af40\dbch\af11\loch\f40 ]}{\rtlch\fcs1 \af0\afs20 \ltrch\fcs0 +\b\fs20\cf20\lang1033\langfe1041\loch\af40\hich\af40\dbch\af11\langfenp1041\insrsid15021189 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\rin0\lin0\itap0\pararsid14363366 {\rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \fs20\cf20\lang1033\langfe1041\loch\af40\hich\af40\dbch\af11\langfenp1041\insrsid14363366 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\rin0\lin0\itap0\pararsid5136836 {\rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \fs20\cf20\lang1033\langfe1041\loch\af40\hich\af40\dbch\af11\langfenp1041\insrsid14363366\charrsid14363366 +\hich\af40\dbch\af11\loch\f40 Autodesk analytics \hich\af40\dbch\af11\loch\f40 programs help us (Autodesk) understand your use of Dynamo so we can personalize your experience and build better online, mobile, and desktop applications.\~ + By analyzing usage trends and patterns we can optimize current features, make positive changes for \hich\af40\dbch\af11\loch\f40 future releases, provide more useful communications, and improve performance and quality.}{\rtlch\fcs1 \af0\afs20 +\ltrch\fcs0 \fs20\cf20\lang1033\langfe1041\loch\af40\hich\af40\dbch\af11\langfenp1041\insrsid7174336\charrsid3037294 +\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a +9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad +5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6 +b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0 +0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6 +a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f +c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512 +0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462 +a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865 +6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b +4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b +4757e8d3f729e245eb2b260a0238fd010000ffff0300504b03041400060008000000210030dd4329a8060000a41b0000160000007468656d652f7468656d652f +7468656d65312e786d6cec594f6fdb3614bf0fd87720746f6327761a07758ad8b19b2d4d1bc46e871e698996d850a240d2497d1bdae38001c3ba618715d86d87 +615b8116d8a5fb34d93a6c1dd0afb0475292c5585e9236d88aad3e2412f9e3fbff1e1fa9abd7eec70c1d1221294fda5efd72cd4324f1794093b0eddd1ef62fad +79482a9c0498f184b4bd2991deb58df7dfbb8ad755446282607d22d771db8b944ad79796a40fc3585ee62949606ecc458c15bc8a702910f808e8c66c69b9565b +5d8a314d3c94e018c8de1a8fa94fd05093f43672e23d06af89927ac06762a049136785c10607758d9053d965021d62d6f6804fc08f86e4bef210c352c144dbab +999fb7b4717509af678b985ab0b6b4ae6f7ed9ba6c4170b06c788a705430adf71bad2b5b057d03606a1ed7ebf5babd7a41cf00b0ef83a6569632cd467faddec9 +699640f6719e76b7d6ac355c7c89feca9cccad4ea7d36c65b258a206641f1b73f8b5da6a6373d9c11b90c537e7f08dce66b7bbeae00dc8e257e7f0fd2badd586 +8b37a088d1e4600ead1ddaef67d40bc898b3ed4af81ac0d76a197c86826828a24bb318f3442d8ab518dfe3a20f000d6458d104a9694ac6d88728eee2782428d6 +0cf03ac1a5193be4cbb921cd0b495fd054b5bd0f530c1931a3f7eaf9f7af9e3f45c70f9e1d3ff8e9f8e1c3e3073f5a42ceaa6d9c84e5552fbffdeccfc71fa33f +9e7ef3f2d117d57859c6fffac327bffcfc793510d26726ce8b2f9ffcf6ecc98baf3efdfdbb4715f04d814765f890c644a29be408edf3181433567125272371be +15c308d3f28acd249438c19a4b05fd9e8a1cf4cd296699771c393ac4b5e01d01e5a30a787d72cf1178108989a2159c77a2d801ee72ce3a5c545a6147f32a9979 +3849c26ae66252c6ed637c58c5bb8b13c7bfbd490a75330f4b47f16e441c31f7184e140e494214d273fc80900aedee52ead87597fa824b3e56e82e451d4c2b4d +32a423279a668bb6690c7e9956e90cfe766cb37b077538abd27a8b1cba48c80acc2a841f12e698f13a9e281c57911ce298950d7e03aba84ac8c154f8655c4f2a +f074481847bd804859b5e696007d4b4edfc150b12addbecba6b18b148a1e54d1bc81392f23b7f84137c2715a851dd0242a633f900710a218ed715505dfe56e86 +e877f0034e16bafb0e258ebb4faf06b769e888340b103d331115bebc4eb813bf83291b63624a0d1475a756c734f9bbc2cd28546ecbe1e20a3794ca175f3fae90 +fb6d2dd99bb07b55e5ccf68942bd0877b23c77b908e8db5f9db7f024d9239010f35bd4bbe2fcae387bfff9e2bc289f2fbe24cfaa301468dd8bd846dbb4ddf1c2 +ae7b4c191ba8292337a469bc25ec3d411f06f53a73e224c5292c8de0516732307070a1c0660d125c7d44553488700a4d7bddd3444299910e254ab984c3a219ae +a4adf1d0f82b7bd46cea4388ad1c12ab5d1ed8e1153d9c9f350a3246aad01c6873462b9ac05999ad5cc988826eafc3acae853a33b7ba11cd1445875ba1b236b1 +399483c90bd560b0b0263435085a21b0f22a9cf9356b38ec6046026d77eba3dc2dc60b17e92219e180643ed27acffba86e9c94c7ca9c225a0f1b0cfae0788ad5 +4adc5a9aec1b703b8b93caec1a0bd8e5de7b132fe5113cf312503b998e2c2927274bd051db6b35979b1ef271daf6c6704e86c73805af4bdd476216c26593af84 +0dfb5393d964f9cc9bad5c313709ea70f561ed3ea7b053075221d51696910d0d339585004b34272bff7213cc7a510a5454a3b349b1b206c1f0af490176745d4b +c663e2abb2b34b23da76f6352ba57ca2881844c1111ab189d8c7e07e1daaa04f40255c77988aa05fe06e4e5bdb4cb9c5394bbaf28d98c1d971ccd20867e556a7 +689ec9166e0a522183792b8907ba55ca6e943bbf2a26e52f48957218ffcf54d1fb09dc3eac04da033e5c0d0b8c74a6b43d2e54c4a10aa511f5fb021a07533b20 +5ae07e17a621a8e082dafc17e450ffb739676998b48643a4daa7211214f623150942f6a02c99e83b85583ddbbb2c4996113211551257a656ec1139246ca86be0 +aadedb3d1441a89b6a929501833b197fee7b9641a3503739e57c732a59b1f7da1cf8a73b1f9bcca0945b874d4393dbbf10b1680f66bbaa5d6f96e77b6f59113d +316bb31a795600b3d256d0cad2fe354538e7566b2bd69cc6cbcd5c38f0e2bcc63058344429dc2121fd07f63f2a7c66bf76e80d75c8f7a1b622f878a18941d840 +545fb28d07d205d20e8ea071b283369834296bdaac75d256cb37eb0bee740bbe278cad253b8bbfcf69eca23973d939b97891c6ce2cecd8da8e2d343578f6648a +c2d0383fc818c798cf64e52f597c740f1cbd05df0c264c49134cf09d4a60e8a107260f20f92d47b374e32f000000ffff0300504b030414000600080000002100 +0dd1909fb60000001b010000270000007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f7 +8277086f6fd3ba109126dd88d0add40384e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89 +d93b64b060828e6f37ed1567914b284d262452282e3198720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd500 +1996509affb3fd381a89672f1f165dfe514173d9850528a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100e9de0f +bfff0000001c0200001300000000000000000000000000000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6 +a7e7c0000000360100000b00000000000000000000000000300100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a +0000001c00000000000000000000000000190200007468656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d00140006000800000021 +0030dd4329a8060000a41b00001600000000000000000000000000d60200007468656d652f7468656d652f7468656d65312e786d6c504b01022d001400060008 +00000021000dd1909fb60000001b0100002700000000000000000000000000b20900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000ad0a00000000} +{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d +617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169 +6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363 +656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e} +{\*\latentstyles\lsdstimax376\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdlocked0 heading 1; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 1; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 2;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 3;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 4; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 5;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 6;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 7; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 8;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 9;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority35 \lsdlocked0 caption; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 5;\lsdqformat1 \lsdpriority10 \lsdlocked0 Title; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority1 \lsdlocked0 Default Paragraph Font;\lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Salutation;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Date; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent;\lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;\lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;\lsdpriority59 \lsdlocked0 Table Grid;\lsdsemihidden1 \lsdlocked0 Placeholder Text; +\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2; +\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2;\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List; +\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1;\lsdpriority61 \lsdlocked0 Light List Accent 1; +\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdsemihidden1 \lsdlocked0 Revision; +\lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1; +\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;\lsdpriority72 \lsdlocked0 Colorful List Accent 1; +\lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2; +\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2; +\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;\lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 2; +\lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3; +\lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3; +\lsdpriority70 \lsdlocked0 Dark List Accent 3;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdpriority60 \lsdlocked0 Light Shading Accent 4; +\lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdpriority62 \lsdlocked0 Light Grid Accent 4;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 4; +\lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdpriority70 \lsdlocked0 Dark List Accent 4; +\lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;\lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdpriority61 \lsdlocked0 Light List Accent 5; +\lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 5; +\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 5; +\lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdpriority62 \lsdlocked0 Light Grid Accent 6; +\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 6; +\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 6; +\lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis; +\lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdsemihidden1 \lsdunhideused1 \lsdpriority37 \lsdlocked0 Bibliography; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;\lsdpriority41 \lsdlocked0 Plain Table 1;\lsdpriority42 \lsdlocked0 Plain Table 2;\lsdpriority43 \lsdlocked0 Plain Table 3;\lsdpriority44 \lsdlocked0 Plain Table 4; +\lsdpriority45 \lsdlocked0 Plain Table 5;\lsdpriority40 \lsdlocked0 Grid Table Light;\lsdpriority46 \lsdlocked0 Grid Table 1 Light;\lsdpriority47 \lsdlocked0 Grid Table 2;\lsdpriority48 \lsdlocked0 Grid Table 3;\lsdpriority49 \lsdlocked0 Grid Table 4; +\lsdpriority50 \lsdlocked0 Grid Table 5 Dark;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 1; +\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 1;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 1;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 1; +\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 1;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 2;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 2; +\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 2;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 2; +\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 3;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 3;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 3;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 3; +\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 3;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 4; +\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 4;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 4;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 4;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 4; +\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 4;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 5; +\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 5;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 5;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 5; +\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 5;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 6;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 6; +\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 6;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 6; +\lsdpriority46 \lsdlocked0 List Table 1 Light;\lsdpriority47 \lsdlocked0 List Table 2;\lsdpriority48 \lsdlocked0 List Table 3;\lsdpriority49 \lsdlocked0 List Table 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark; +\lsdpriority51 \lsdlocked0 List Table 6 Colorful;\lsdpriority52 \lsdlocked0 List Table 7 Colorful;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 List Table 2 Accent 1;\lsdpriority48 \lsdlocked0 List Table 3 Accent 1; +\lsdpriority49 \lsdlocked0 List Table 4 Accent 1;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 1;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 1; +\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 List Table 2 Accent 2;\lsdpriority48 \lsdlocked0 List Table 3 Accent 2;\lsdpriority49 \lsdlocked0 List Table 4 Accent 2; +\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 2;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 3; +\lsdpriority47 \lsdlocked0 List Table 2 Accent 3;\lsdpriority48 \lsdlocked0 List Table 3 Accent 3;\lsdpriority49 \lsdlocked0 List Table 4 Accent 3;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 3; +\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 4;\lsdpriority47 \lsdlocked0 List Table 2 Accent 4; +\lsdpriority48 \lsdlocked0 List Table 3 Accent 4;\lsdpriority49 \lsdlocked0 List Table 4 Accent 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 4;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 4; +\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5; +\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5; +\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6; +\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Mention; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hashtag;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Unresolved Mention;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Link;}}{\*\datastore 01050000 +02000000180000004d73786d6c322e534158584d4c5265616465722e362e3000000000000000000000060000 +d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff0c6ad98892f1d411a65f0040963251e500000000000000000000000080f9 +619d9b19da01feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000105000000000000}} \ No newline at end of file diff --git a/src/Config/CS_SDK.props b/src/Config/CS_SDK.props index 3f3c1037183..09ae2fd3263 100644 --- a/src/Config/CS_SDK.props +++ b/src/Config/CS_SDK.props @@ -21,8 +21,6 @@ en-US Library false - true - false @@ -87,10 +85,10 @@ false - + $(OutputPath)\..\..\..\test\test_dependencies - + all runtime @@ -148,4 +146,4 @@ - + \ No newline at end of file diff --git a/src/DynamoCore/Configuration/PreferenceSettings.cs b/src/DynamoCore/Configuration/PreferenceSettings.cs index 9c90e5f897c..74df12158a7 100644 --- a/src/DynamoCore/Configuration/PreferenceSettings.cs +++ b/src/DynamoCore/Configuration/PreferenceSettings.cs @@ -69,6 +69,7 @@ internal readonly static Lazy private bool isTimeStampIncludedInExportFilePath; private bool isCreatedFromValidFile = true; private string backupLocation; + private bool isMLAutocompleteTOUApproved; #region Constants /// @@ -696,6 +697,21 @@ public bool EnableStaticSplashScreen } } + /// + /// This defines if the user is agree to the ML Automcomplete Terms of Use + /// + public bool IsMLAutocompleteTOUApproved + { + get + { + return isMLAutocompleteTOUApproved; + } + set + { + isMLAutocompleteTOUApproved = value; + } + } + /// /// Engine used by default for new Python script and string nodes. If not empty, this takes precedence over any system settings. /// @@ -932,6 +948,7 @@ public PreferenceSettings() DynamoPlayerFolderGroups = new List(); backupLocation = string.Empty; GraphChecksumItemsList = new List(); + isMLAutocompleteTOUApproved = false; } /// diff --git a/src/DynamoCore/DynamoCore.csproj b/src/DynamoCore/DynamoCore.csproj index 0e1dba3383d..85f779d8437 100644 --- a/src/DynamoCore/DynamoCore.csproj +++ b/src/DynamoCore/DynamoCore.csproj @@ -136,6 +136,7 @@ + diff --git a/src/DynamoCore/Models/DynamoModel.cs b/src/DynamoCore/Models/DynamoModel.cs index cb13dd6ceed..3d2896d6908 100644 --- a/src/DynamoCore/Models/DynamoModel.cs +++ b/src/DynamoCore/Models/DynamoModel.cs @@ -537,7 +537,7 @@ public interface IStartConfiguration bool NoNetworkMode => false; /// - /// Configuration object that contains host information like Host name, version and session id. + /// Configuration object that contains host information like Host name, parent id and session id. /// HostAnalyticsInfo HostAnalyticsInfo { get; set; } } diff --git a/src/DynamoCoreWpf/Controls/InPortContextMenu.xaml.cs b/src/DynamoCoreWpf/Controls/InPortContextMenu.xaml.cs index 81df82642b9..3693155b8e9 100644 --- a/src/DynamoCoreWpf/Controls/InPortContextMenu.xaml.cs +++ b/src/DynamoCoreWpf/Controls/InPortContextMenu.xaml.cs @@ -1,6 +1,7 @@ -using System; +using System; using System.Windows; using System.Windows.Controls; +using Dynamo.Models; using Dynamo.ViewModels; namespace Dynamo.UI.Controls @@ -15,8 +16,10 @@ public partial class InPortContextMenu : UserControl public InPortContextMenu() { InitializeComponent(); - - if (Application.Current != null) Application.Current.Deactivated += CurrentApplicationDeactivated; + if (string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName) && Application.Current != null) + { + Application.Current.Deactivated += CurrentApplicationDeactivated; + } Unloaded += InPortContextMenuControl_Unloaded; } @@ -27,7 +30,7 @@ public InPortContextMenu() /// private void InPortContextMenuControl_Unloaded(object sender, RoutedEventArgs e) { - if (Application.Current != null) + if (string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName) && Application.Current != null) { Application.Current.Deactivated -= CurrentApplicationDeactivated; } diff --git a/src/DynamoCoreWpf/Controls/IncanvasSearchControl.xaml.cs b/src/DynamoCoreWpf/Controls/IncanvasSearchControl.xaml.cs index 069a5ee6c09..b8f40090618 100644 --- a/src/DynamoCoreWpf/Controls/IncanvasSearchControl.xaml.cs +++ b/src/DynamoCoreWpf/Controls/IncanvasSearchControl.xaml.cs @@ -8,6 +8,7 @@ using System.Windows.Input; using System.Windows.Threading; using Dynamo.Logging; +using Dynamo.Models; using Dynamo.Utilities; using Dynamo.ViewModels; using Dynamo.Wpf.ViewModels; @@ -31,7 +32,7 @@ public SearchViewModel ViewModel public InCanvasSearchControl() { InitializeComponent(); - if (Application.Current != null) + if (string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName) && Application.Current != null) { Application.Current.Deactivated += CurrentApplicationDeactivated; Application.Current.MainWindow.Closing += InCanvasSearchControl_Unloaded; @@ -40,7 +41,7 @@ public InCanvasSearchControl() private void InCanvasSearchControl_Unloaded(object sender, System.ComponentModel.CancelEventArgs e) { - if (Application.Current != null) + if (string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName) && Application.Current != null) { Application.Current.Deactivated -= CurrentApplicationDeactivated; Application.Current.MainWindow.Closing -= InCanvasSearchControl_Unloaded; diff --git a/src/DynamoCoreWpf/Controls/NodeAutoCompleteSearchControl.xaml.cs b/src/DynamoCoreWpf/Controls/NodeAutoCompleteSearchControl.xaml.cs index d7ddfd9c860..d11e8d4033d 100644 --- a/src/DynamoCoreWpf/Controls/NodeAutoCompleteSearchControl.xaml.cs +++ b/src/DynamoCoreWpf/Controls/NodeAutoCompleteSearchControl.xaml.cs @@ -42,10 +42,10 @@ public partial class NodeAutoCompleteSearchControl : IDisposable public NodeAutoCompleteSearchControl() { InitializeComponent(); - if (Application.Current != null) + if (string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName) && Application.Current != null) { Application.Current.Deactivated += CurrentApplicationDeactivated; - if (Application.Current.MainWindow != null) + if (Application.Current?.MainWindow != null) { Application.Current.MainWindow.Closing += NodeAutoCompleteSearchControl_Unloaded; } @@ -55,10 +55,10 @@ public NodeAutoCompleteSearchControl() private void NodeAutoCompleteSearchControl_Unloaded(object sender, System.ComponentModel.CancelEventArgs e) { - if (Application.Current != null) + if (string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName) && Application.Current != null) { Application.Current.Deactivated -= CurrentApplicationDeactivated; - if (Application.Current.MainWindow != null) + if (Application.Current?.MainWindow != null) { Application.Current.MainWindow.Closing -= NodeAutoCompleteSearchControl_Unloaded; } diff --git a/src/DynamoCoreWpf/Controls/OutPortContextMenu.xaml.cs b/src/DynamoCoreWpf/Controls/OutPortContextMenu.xaml.cs index 2814b5439a8..8a32e380741 100644 --- a/src/DynamoCoreWpf/Controls/OutPortContextMenu.xaml.cs +++ b/src/DynamoCoreWpf/Controls/OutPortContextMenu.xaml.cs @@ -1,6 +1,7 @@ using System; using System.Windows; using System.Windows.Controls; +using Dynamo.Models; using Dynamo.ViewModels; namespace Dynamo.UI.Controls @@ -19,7 +20,10 @@ public OutPortContextMenu() { InitializeComponent(); - if (Application.Current != null) Application.Current.Deactivated += CurrentApplicationDeactivated; + if (string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName) && Application.Current != null) + { + Application.Current.Deactivated += CurrentApplicationDeactivated; + } Unloaded += OutPortContextMenuControl_Unloaded; } @@ -30,7 +34,7 @@ public OutPortContextMenu() /// private void OutPortContextMenuControl_Unloaded(object sender, RoutedEventArgs e) { - if (Application.Current != null) + if (string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName) && Application.Current != null) { Application.Current.Deactivated -= CurrentApplicationDeactivated; } diff --git a/src/DynamoCoreWpf/Properties/Resources.Designer.cs b/src/DynamoCoreWpf/Properties/Resources.Designer.cs index 0babc37aced..7c8639ccfa4 100644 --- a/src/DynamoCoreWpf/Properties/Resources.Designer.cs +++ b/src/DynamoCoreWpf/Properties/Resources.Designer.cs @@ -159,6 +159,15 @@ public static string AddToLibraryButton { } } + /// + /// Looks up a localized string similar to I agree to ML Node Autocomplete Terms of Use. + /// + public static string AgreeToMLAutocompleteTOUText { + get { + return ResourceManager.GetString("AgreeToMLAutocompleteTOUText", resourceCulture); + } + } + /// /// Looks up a localized string similar to Autodesk A360. /// @@ -2270,7 +2279,7 @@ public static string DynamoViewSettingMenuNumberFormat { } /// - /// Looks up a localized string similar to Agreement to _Collect Usability Data. + /// Looks up a localized string similar to Agreement and _Terms of Use. /// public static string DynamoViewSettingMenuShowDataReportingDialog { get { @@ -2279,7 +2288,7 @@ public static string DynamoViewSettingMenuShowDataReportingDialog { } /// - /// Looks up a localized string similar to Display the dialog for user to pick agreement on data collecting.. + /// Looks up a localized string similar to Display the dialog of agreement on data collecting and Machine Learning Node Autocomplete terms of use. /// public static string DynamoViewSettingMenuShowDataReportingDialogTooltip { get { @@ -9872,7 +9881,7 @@ public static string UpdateMessage { } /// - /// Looks up a localized string similar to Agreement to Collect Usability Data. + /// Looks up a localized string similar to Agreement and Terms of Use. /// public static string UsageReportPromptDialogTitle { get { diff --git a/src/DynamoCoreWpf/Properties/Resources.en-US.resx b/src/DynamoCoreWpf/Properties/Resources.en-US.resx index a0feea9c301..b6debbf8ac9 100644 --- a/src/DynamoCoreWpf/Properties/Resources.en-US.resx +++ b/src/DynamoCoreWpf/Properties/Resources.en-US.resx @@ -764,7 +764,7 @@ Don't worry, you'll have the option to save your work. Setting menu | Decimal inch - Agreement to _Collect Usability Data + Agreement and _Terms of Use Dynamo menu | Show user agreement dialog about data collecting @@ -2217,7 +2217,10 @@ Installing the latest update requires Dynamo and any host applications to close. Do you want to install the latest Dynamo update? - Agreement to Collect Usability Data + Agreement and Terms of Use + + + I agree to ML Node Autocomplete Terms of Use Keep 1 input list's nesting @@ -2310,7 +2313,7 @@ Uninstall the following packages: {0}? Filter by - Display the dialog for user to pick agreement on data collecting. + Display the dialog of agreement on data collecting and Machine Learning Node Autocomplete terms of use @@ -3852,4 +3855,4 @@ In certain complex graphs or host program scenarios, Automatic mode may cause in Element Binding allows a two-way interaction between Dynamo and the host application like Revit or Civil3D where a user can select an element in the host document and have Dynamo "bind" that element to a node in the workspace. - + \ No newline at end of file diff --git a/src/DynamoCoreWpf/Properties/Resources.resx b/src/DynamoCoreWpf/Properties/Resources.resx index c18d807513c..ce39b9a0471 100644 --- a/src/DynamoCoreWpf/Properties/Resources.resx +++ b/src/DynamoCoreWpf/Properties/Resources.resx @@ -487,7 +487,7 @@ Setting menu | Decimal inch - Agreement to _Collect Usability Data + Agreement and _Terms of Use Dynamo menu | Show user agreement dialog about data collecting @@ -1151,7 +1151,10 @@ Don't worry, you'll have the option to save your work. Cancel - Agreement to Collect Usability Data + Agreement and Terms of Use + + + I agree to ML Node Autocomplete Terms of Use Clear @@ -1306,7 +1309,7 @@ Don't worry, you'll have the option to save your work. Once you install a package, you can find it here. - + Sign in to your Dynamo account to view your published packages. @@ -1683,7 +1686,7 @@ If the toggle is off custom packages that are not already loaded will load once The package's copyright holder. - + The package's licence. @@ -2600,7 +2603,7 @@ Uninstall the following packages: {0}? Filter by - Display the dialog for user to pick agreement on data collecting. + Display the dialog of agreement on data collecting and Machine Learning Node Autocomplete terms of use diff --git a/src/DynamoCoreWpf/Services/UsageReportingManager.cs b/src/DynamoCoreWpf/Services/UsageReportingManager.cs index 4a78202266f..4c09d4aae9e 100644 --- a/src/DynamoCoreWpf/Services/UsageReportingManager.cs +++ b/src/DynamoCoreWpf/Services/UsageReportingManager.cs @@ -105,15 +105,14 @@ public void ToggleIsAnalyticsReportingApproved(object parameter) private void ShowUsageReportingPrompt(Window ownerWindow) { // If an owner window is not supplied, then we will fallback onto - // using the application's main window. In native host application - // scenario (e.g. Revit), the "Application.Current" will be "null". + // using the application's main window. // The owner window is important so that usage report window always // get shown on top of the owner window, otherwise it is possible // for usage report window to show up in the background (behind all // other full screen windows), and Dynamo main window will appear // to be frozen because control cannot return to it. // - if (ownerWindow == null && (null != Application.Current)) + if (ownerWindow == null && string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName) && Application.Current != null) ownerWindow = Application.Current.MainWindow; var usageReportingPrompt = new UsageReportingAgreementPrompt(resourceProvider, dynamoViewModel) diff --git a/src/DynamoCoreWpf/UI/Prompts/UsageReportingAgreementPrompt.xaml b/src/DynamoCoreWpf/UI/Prompts/UsageReportingAgreementPrompt.xaml index 3e2799edf75..4e942380ab7 100644 --- a/src/DynamoCoreWpf/UI/Prompts/UsageReportingAgreementPrompt.xaml +++ b/src/DynamoCoreWpf/UI/Prompts/UsageReportingAgreementPrompt.xaml @@ -7,7 +7,7 @@ WindowStyle="None" MinWidth="530" MaxWidth="650" - Height="310" + Height="485" ResizeMode="NoResize" ShowInTaskbar="False" AllowsTransparency="True" @@ -98,6 +98,8 @@ + + @@ -178,19 +180,53 @@ Background="Transparent" OpenLinksInBrowser="True" BorderThickness="0" /> + + + + + + + + + + + + + - public override void Dispose() { - foreach (var category in SubCategories) - category.PropertyChanged -= CategoryOnPropertyChanged; + if (SubCategories != null) + { + foreach (var category in SubCategories) + category.PropertyChanged -= CategoryOnPropertyChanged; + } - foreach (var item in Items) - item.PropertyChanged -= ItemOnPropertyChanged; + if (Items != null) + { + foreach (var item in Items) + item.PropertyChanged -= ItemOnPropertyChanged; + Items.CollectionChanged -= ItemsOnCollectionChanged; + } + + if (Entries != null) Entries.CollectionChanged -= OnCollectionChanged; + if (SubCategories != null) SubCategories.CollectionChanged -= SubCategoriesOnCollectionChanged; - Entries.CollectionChanged -= OnCollectionChanged; - SubCategories.CollectionChanged -= SubCategoriesOnCollectionChanged; - Items.CollectionChanged -= ItemsOnCollectionChanged; base.Dispose(); } @@ -389,11 +397,17 @@ public void DisposeTree() { Dispose(); - foreach (var entry in Entries) - entry.Dispose(); + if (Entries != null) + { + foreach (var entry in Entries) + entry.Dispose(); + } - foreach (var subCategory in SubCategories) - subCategory.DisposeTree(); + if (SubCategories != null) + { + foreach (var subCategory in SubCategories) + subCategory.DisposeTree(); + } } private void CategoryOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) diff --git a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs index 388d86343b4..adb9b340382 100644 --- a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs @@ -256,7 +256,7 @@ public DynamoView(DynamoViewModel dynamoViewModel) { fileTrustWarningPopup = new FileTrustWarning(this); } - if (!DynamoModel.IsTestMode && Application.Current != null) + if (!DynamoModel.IsTestMode && string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName) && Application.Current != null) { Application.Current.MainWindow = this; } @@ -1372,9 +1372,10 @@ private void DynamoView_Loaded(object sender, EventArgs e) TrackStartupAnalytics(); - // In native host scenario (e.g. Revit), the "Application.Current" will be "null". Therefore, the InCanvasSearchControl.OnRequestShowInCanvasSearch - // will not work. Instead, we have to check if the Owner Window (DynamoView) is deactivated or not. - if (Application.Current == null) + // In native host scenario (e.g. Revit), the InCanvasSearchControl.OnRequestShowInCanvasSearch + // will not work. Instead, we have to check if the Owner Window (DynamoView) is deactivated or not. + + if (!string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName)) { this.Deactivated += (s, args) => { HidePopupWhenWindowDeactivated(null); }; } @@ -2033,6 +2034,7 @@ private void WindowClosed(object sender, EventArgs e) this.Dispose(); sharedViewExtensionLoadedParams?.Dispose(); this._pkgSearchVM?.Dispose(); + this._pkgVM?.Dispose(); } // the key press event is being intercepted before it can get to diff --git a/src/DynamoCoreWpf/Views/PackageManager/Controls/PackageManagerPublishControl.xaml.cs b/src/DynamoCoreWpf/Views/PackageManager/Controls/PackageManagerPublishControl.xaml.cs index 5eca00d67bd..301562397f8 100644 --- a/src/DynamoCoreWpf/Views/PackageManager/Controls/PackageManagerPublishControl.xaml.cs +++ b/src/DynamoCoreWpf/Views/PackageManager/Controls/PackageManagerPublishControl.xaml.cs @@ -79,6 +79,7 @@ private void SetDataContext() InitializePages(); this.mainFrame.NavigationService.Navigate(PublishPages[0]); + this.Loaded -= InitializeContext; } public void Dispose() @@ -87,8 +88,12 @@ public void Dispose() Actions.Close, Categories.PackageManagerOperations); - PublishPackageViewModel.PublishSuccess -= PackageViewModelOnPublishSuccess; - PublishPackageViewModel.RequestShowFolderBrowserDialog -= OnRequestShowFolderBrowserDialog; + if(PublishPackageViewModel != null ) + { + PublishPackageViewModel.PublishSuccess -= PackageViewModelOnPublishSuccess; + PublishPackageViewModel.RequestShowFolderBrowserDialog -= OnRequestShowFolderBrowserDialog; + + } this.Loaded -= InitializeContext; @@ -98,7 +103,9 @@ public void Dispose() PublishPages = null; NavButtonStacks = null; - Breadcrumbs.Clear(); + Breadcrumbs?.Clear(); + + this.DataContextChanged -= ThisDataContextChanged; } private void InitializePages() @@ -126,6 +133,8 @@ private void InitializePages() private void PackageViewModelOnPublishSuccess(PublishPackageViewModel sender) { + if (PublishPages == null) return; + statusLabel.Visibility = Visibility.Collapsed; currentPage = 3; @@ -295,6 +304,8 @@ private void ToggleButtonRowVisibility(int page) private void DisposePages() { + if (PublishPages == null || !PublishPages.Any()) return; + foreach(var page in PublishPages.Values) { if (page is PublishPackagePublishPage) @@ -312,22 +323,21 @@ private void mainFrame_Navigated(object sender, System.Windows.Navigation.Naviga { Page navigatedPage = e.Content as Page; + if (navigatedPage == null || PublishPages == null || !PublishPages.Any()) return; + PublishPages.Values.ToList().ForEach(page => { page.IsEnabled = false; }); - Dispatcher.BeginInvoke((Action)(() => + if (navigatedPage != null) { - if (navigatedPage != null) - { - if (navigatedPage is PublishPackagePublishPage) - (navigatedPage as PublishPackagePublishPage).LoadEvents(); - if (navigatedPage is PublishPackageSelectPage) - (navigatedPage as PublishPackageSelectPage).LoadEvents(); - if (navigatedPage is PublishPackagePreviewPage) - (navigatedPage as PublishPackagePreviewPage).LoadEvents(); - if (navigatedPage is PublishPackageFinishPage) - (navigatedPage as PublishPackageFinishPage).IsEnabled = true; - } - })); + if (navigatedPage is PublishPackagePublishPage) + (navigatedPage as PublishPackagePublishPage).LoadEvents(); + if (navigatedPage is PublishPackageSelectPage) + (navigatedPage as PublishPackageSelectPage).LoadEvents(); + if (navigatedPage is PublishPackagePreviewPage) + (navigatedPage as PublishPackagePreviewPage).LoadEvents(); + if (navigatedPage is PublishPackageFinishPage) + (navigatedPage as PublishPackageFinishPage).IsEnabled = true; + } } private void CancelButton_Click(object sender, RoutedEventArgs e) diff --git a/src/DynamoCoreWpf/Views/PackageManager/PackageManagerView.xaml.cs b/src/DynamoCoreWpf/Views/PackageManager/PackageManagerView.xaml.cs index fe1a016f7e4..f5840529ff8 100644 --- a/src/DynamoCoreWpf/Views/PackageManager/PackageManagerView.xaml.cs +++ b/src/DynamoCoreWpf/Views/PackageManager/PackageManagerView.xaml.cs @@ -127,8 +127,10 @@ private void CloseButton_Click(object sender, RoutedEventArgs e) private void WindowClosed(object sender, EventArgs e) { - this.packageManagerPublish.Dispose(); - this.packageManagerSearch.Dispose(); + this.packageManagerPublish?.Dispose(); + this.packageManagerSearch?.Dispose(); + + if (PackageManagerViewModel == null) return; this.PackageManagerViewModel.PackageSearchViewModel.RequestShowFileDialog -= OnRequestShowFileDialog; this.PackageManagerViewModel.PackageSearchViewModel.PackageManagerViewClose(); this.PackageManagerViewModel.PublishPackageViewModel.CancelCommand.Execute(); diff --git a/src/DynamoCoreWpf/Views/PackageManager/Pages/PublishPackagePreviewPage.xaml.cs b/src/DynamoCoreWpf/Views/PackageManager/Pages/PublishPackagePreviewPage.xaml.cs index 1d1cbb98310..16826c28ba7 100644 --- a/src/DynamoCoreWpf/Views/PackageManager/Pages/PublishPackagePreviewPage.xaml.cs +++ b/src/DynamoCoreWpf/Views/PackageManager/Pages/PublishPackagePreviewPage.xaml.cs @@ -43,7 +43,7 @@ public void Dispose() { this.PublishPackageViewModel = null; this.DataContextChanged -= PublishPackagePublishPage_DataContextChanged; - this.customBrowserControl.Dispose(); + this.customBrowserControl?.Dispose(); } private void customBrowserControl_Loaded(object sender, RoutedEventArgs e) diff --git a/src/DynamoCoreWpf/Views/PackageManager/Pages/PublishPackagePublishPage.xaml.cs b/src/DynamoCoreWpf/Views/PackageManager/Pages/PublishPackagePublishPage.xaml.cs index e0420424542..84e1a796522 100644 --- a/src/DynamoCoreWpf/Views/PackageManager/Pages/PublishPackagePublishPage.xaml.cs +++ b/src/DynamoCoreWpf/Views/PackageManager/Pages/PublishPackagePublishPage.xaml.cs @@ -88,7 +88,7 @@ public void Dispose() { this.PublishPackageViewModel = null; this.DataContextChanged -= PublishPackagePublishPage_DataContextChanged; - this.previewBrowserControl.Dispose(); + this.previewBrowserControl?.Dispose(); } private void NavigationButton_Click(object sender, RoutedEventArgs e) diff --git a/src/DynamoCoreWpf/Views/PackageManager/Pages/PublishPackageSelectPage.xaml.cs b/src/DynamoCoreWpf/Views/PackageManager/Pages/PublishPackageSelectPage.xaml.cs index 4307ccbbbc5..a5132dc1aac 100644 --- a/src/DynamoCoreWpf/Views/PackageManager/Pages/PublishPackageSelectPage.xaml.cs +++ b/src/DynamoCoreWpf/Views/PackageManager/Pages/PublishPackageSelectPage.xaml.cs @@ -77,10 +77,10 @@ internal void LoadEvents() public void Dispose() { - this.ItemSelection.Clear(); + this.ItemSelection?.Clear(); this.PublishPackageViewModel = null; this.DataContextChanged -= PublishPackagePublishPage_DataContextChanged; - this.customBrowserControl.Dispose(); + this.customBrowserControl?.Dispose(); } private void customBrowserControl_Loaded(object sender, RoutedEventArgs e) diff --git a/src/DynamoPackages/PackageDirectoryBuilder.cs b/src/DynamoPackages/PackageDirectoryBuilder.cs index 02ec141615d..6189e9b8222 100644 --- a/src/DynamoPackages/PackageDirectoryBuilder.cs +++ b/src/DynamoPackages/PackageDirectoryBuilder.cs @@ -57,7 +57,7 @@ public IDirectoryInfo BuildDirectory(Package package, string packagesDirectory, WritePackageHeader(package, rootDir); RemoveUnselectedFiles(contentFiles, rootDir); CopyFilesIntoPackageDirectory(contentFiles, markdownFiles, dyfDir, binDir, extraDir, docDir); - RemoveDyfFiles(contentFiles, dyfDir); // Why do we need to remove the dyf files from the publishing folder? + RemoveDyfFiles(contentFiles, dyfDir); RemapCustomNodeFilePaths(contentFiles, dyfDir.FullName); @@ -77,7 +77,7 @@ public IDirectoryInfo BuildRetainDirectory(Package package, string packagesDirec RemoveUnselectedFiles(contentFiles.SelectMany(files => files).ToList(), rootDir); CopyFilesIntoRetainedPackageDirectory(contentFiles, markdownFiles, rootDir, out dyfFiles); - RemoveRetainDyfFiles(contentFiles.SelectMany(files => files).ToList(), dyfFiles); // Why do we need to remove the dyf files from the publishing folder? + RemoveRetainDyfFiles(contentFiles.SelectMany(files => files).ToList(), dyfFiles); RemapRetainCustomNodeFilePaths(contentFiles.SelectMany(files => files).ToList(), dyfFiles); diff --git a/src/DynamoPackages/PackageUploadBuilder.cs b/src/DynamoPackages/PackageUploadBuilder.cs index 43892501aeb..390f1a9ae75 100644 --- a/src/DynamoPackages/PackageUploadBuilder.cs +++ b/src/DynamoPackages/PackageUploadBuilder.cs @@ -127,7 +127,6 @@ public PackageVersionUpload NewPackageVersionUpload(Package package, string pack /// /// Build a new version of the package and upload retaining folder structure - /// TODO: Should that be a separate method or an override? Break API ok? /// /// /// diff --git a/src/DynamoUtilities/CLIWrapper.cs b/src/DynamoUtilities/CLIWrapper.cs new file mode 100644 index 00000000000..5578e233867 --- /dev/null +++ b/src/DynamoUtilities/CLIWrapper.cs @@ -0,0 +1,175 @@ +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Threading.Tasks; + +namespace Dynamo.Utilities +{ + /// + /// Base class for Dynamo CLI wrappers + /// + internal abstract class CLIWrapper : IDisposable + { + protected const string endOfDataToken = @"<<<<>>>>"; + protected const string startofDataToken = @"<<<<>>>>"; + protected readonly Process process = new Process(); + protected bool started; + internal event Action MessageLogged; + + public virtual void Dispose() + { + process.ErrorDataReceived -= Process_ErrorDataReceived; + KillProcess(); + } + + /// + /// Start the process. + /// + /// relative path to the exe to start. + /// argument string to pass to process. + protected virtual void StartProcess(string relativeEXEPath, string argString) + { + ProcessStartInfo startInfo = new ProcessStartInfo + { + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardInput = true, + RedirectStandardError = true, + + UseShellExecute = false, + Arguments = argString, + FileName = GetToolPath(relativeEXEPath) + }; + + process.StartInfo = startInfo; + try + { + process.Start(); + started = true; + //the only purpose here is to avoid deadlocks when std err gets filled up 4kb + //in long running processes. + process.ErrorDataReceived += Process_ErrorDataReceived; + process.BeginErrorReadLine(); + + } + catch (Win32Exception) + { + // Do nothing + } + } + + private void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e) + { + //do nothing, we just want to empty the error stream. + } + + + + /// + /// Kill the CLI tool - if running + /// + protected void KillProcess() + { + if (started) + { + if (!process.HasExited) + { + process.Kill(); + } + started = false; + } + process.Dispose(); + } + /// + /// Compute the location of the CLI tool. + /// + /// Returns full path to the CLI tool + protected static string GetToolPath(string relativePath) + { + var rootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new ArgumentNullException(nameof(Path.GetDirectoryName)); + var toolPath = Path.Combine(rootPath,relativePath); + return toolPath; + } + /// + /// Read data from CLI tool + /// + /// will return empty string if we don't finish reading all data in the timeout provided in milliseconds. + /// + protected virtual async Task GetData(int timeoutms) + { + var readStdOutTask = Task.Run(() => + { + if (process.HasExited) + { + return string.Empty; + } + + using (var writer = new StringWriter()) + { + var done = false; + var start = false; + while (!done) + { + try + { + var line = process.StandardOutput.ReadLine(); + MessageLogged?.Invoke(line); + if (line == null || line == startofDataToken) + { + start = true; + continue; //don't record start token to stream. + } + + if (line == null || line == endOfDataToken) + { + done = true; + } + else + { + //if we have started recieving valid data, start recording + if (!string.IsNullOrWhiteSpace(line) && start) + { + writer.WriteLine(line); + } + } + } + catch (Exception) + { + KillProcess(); + return GetCantCommunicateErrorMessage(); + } + } + + return writer.ToString(); + } + }); + var completedTask = await Task.WhenAny(readStdOutTask, Task.Delay(TimeSpan.FromMilliseconds(timeoutms))); + //if the completed task was our read std out task, then return the data + //else we timed out, so return an empty string. + return completedTask == readStdOutTask ? readStdOutTask.Result : string.Empty; + } + + protected void RaiseMessageLogged(string message) + { + MessageLogged?.Invoke(message); + } + + /// + /// Can't start Error message + /// + /// Returns error message + protected abstract string GetCantStartErrorMessage(); + + + /// + /// Can't communicate Error message + /// + /// Returns error message + protected abstract string GetCantCommunicateErrorMessage(); + + + + } +} diff --git a/src/DynamoUtilities/DynamoFeatureFlagsManager.cs b/src/DynamoUtilities/DynamoFeatureFlagsManager.cs index e4237cbd4b7..d60c886c7c9 100644 --- a/src/DynamoUtilities/DynamoFeatureFlagsManager.cs +++ b/src/DynamoUtilities/DynamoFeatureFlagsManager.cs @@ -24,6 +24,16 @@ internal class DynamoFeatureFlagsManager : CLIWrapper private Dictionary AllFlagsCache { get; set; }//TODO lock is likely overkill. private SynchronizationContext syncContext; internal static event Action FlagsRetrieved; + + //TODO(DYN-6464)- remove this field!. + /// + /// set to true after some FF issue is logged. For now we only log once to avoid clients overwhelming the logger. + /// + private bool loggedFFIssueOnce = false; + /// + /// Timeout in ms for feature flag communication with CLI process. + /// + private const int featureFlagTimeoutMs = 5000; /// /// Constructor @@ -54,18 +64,18 @@ internal void CacheAllFlags() { //wait for response - var dataFromCLI = GetData(); + var dataFromCLI = GetData(featureFlagTimeoutMs).Result; //convert from json string to dictionary. try - { + { AllFlagsCache = JsonConvert.DeserializeObject>(dataFromCLI); //invoke the flags retrieved event on the sync context which should be the main ui thread. syncContext?.Send((_) => - { + { FlagsRetrieved?.Invoke(); - },null); - + }, null); + } catch (Exception e) { @@ -74,34 +84,45 @@ internal void CacheAllFlags() } /// - /// Check feature flag value, if not exist, return defaultval + /// Check feature flag value, if it does not exist, return the defaultval. /// - /// - /// - /// + /// Must be a bool or string, only bool or string flags should be created unless this implementation is improved. + /// feature flag name + /// Currently the flag and default val MUST be a bool or string. /// internal T CheckFeatureFlag(string featureFlagKey, T defaultval) { if(!(defaultval is bool || defaultval is string)){ - RaiseMessageLogged("unsupported flag type"); - return defaultval; + throw new ArgumentException("unsupported flag type", defaultval.GetType().ToString()); } // if we have not retrieved flags from the cli return empty - // and log. + // and log once. if(AllFlagsCache == null) - { - RaiseMessageLogged("the flags cache is null, something went wrong retrieving feature flags," + - " or you need to wait longer for the cache to populate, you can use the static FlagsRetrieved event for this purpose. "); + { //TODO(DYN-6464) Revisit this and log more when the logger is not easily overwhelmed. + if (!loggedFFIssueOnce) + { + RaiseMessageLogged( + $"The flags cache was null while checking {featureFlagKey}, something went wrong retrieving feature flags," + + " or you need to wait longer for the cache to populate before checking for flags, you can use the static FlagsRetrieved event for this purpose." + + "This message will not be logged again, and future calls to CheckFeatureFlags will return default values!!!"); + } + + loggedFFIssueOnce = true; return defaultval; } - if (AllFlagsCache.ContainsKey(featureFlagKey)) + if (AllFlagsCache.TryGetValue(featureFlagKey, out var flagVal)) { - return (T)AllFlagsCache[featureFlagKey]; + return (T)flagVal; } else { - RaiseMessageLogged($"failed to get value for feature flag key ex: {featureFlagKey},{System.Environment.NewLine} returning default value: {defaultval}"); + if (!loggedFFIssueOnce) + { + RaiseMessageLogged( + $"failed to get value for feature flag key ex: {featureFlagKey},{System.Environment.NewLine} returning default value: {defaultval}"); + } + loggedFFIssueOnce = true; return defaultval; } } diff --git a/src/DynamoUtilities/Md2Html.cs b/src/DynamoUtilities/Md2Html.cs index 763134589a8..ceb5908b2a7 100644 --- a/src/DynamoUtilities/Md2Html.cs +++ b/src/DynamoUtilities/Md2Html.cs @@ -1,168 +1,11 @@ using System; -using System.ComponentModel; -using System.Diagnostics; using System.IO; -using System.Reflection; +using System.Threading; using DynamoUtilities.Properties; +using Newtonsoft.Json.Linq; namespace Dynamo.Utilities { - //TODO move to new file. - /// - /// Base class for Dynamo CLI wrappers - /// - internal abstract class CLIWrapper : IDisposable - { - protected const string endOfDataToken = @"<<<<>>>>"; - protected const string startofDataToken = @"<<<<>>>>"; - protected readonly Process process = new Process(); - protected bool started; - internal event Action MessageLogged; - - public virtual void Dispose() - { - process.ErrorDataReceived -= Process_ErrorDataReceived; - KillProcess(); - } - - /// - /// Start the process. - /// - /// relative path to the exe to start. - /// argument string to pass to process. - protected virtual void StartProcess(string relativeEXEPath, string argString) - { - ProcessStartInfo startInfo = new ProcessStartInfo - { - CreateNoWindow = true, - RedirectStandardOutput = true, - RedirectStandardInput = true, - RedirectStandardError = true, - - UseShellExecute = false, - Arguments = argString, - FileName = GetToolPath(relativeEXEPath) - }; - - process.StartInfo = startInfo; - try - { - process.Start(); - started = true; - //the only purspose here is to avoid deadlocks when std err gets filled up 4kb - //in long running processes. - process.ErrorDataReceived += Process_ErrorDataReceived; - process.BeginErrorReadLine(); - - } - catch (Win32Exception) - { - // Do nothing - } - } - - private void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e) - { - //do nothing, we just want to empty the error stream. - } - - - - /// - /// Kill the CLI tool - if running - /// - protected void KillProcess() - { - if (started) - { - if (!process.HasExited) - { - process.Kill(); - } - started = false; - } - process.Dispose(); - } - /// - /// Compute the location of the CLI tool. - /// - /// Returns full path to the CLI tool - protected static string GetToolPath(string relativePath) - { - var rootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? throw new ArgumentNullException(nameof(Path.GetDirectoryName)); - var toolPath = Path.Combine(rootPath,relativePath); - return toolPath; - } - //TODO if we see any issues with deadlocks we can try using a timeout on another thread. - /// - /// Read data from CLI tool - /// Returns data read from CLI tool - /// - protected virtual string GetData() - { - if (process.HasExited) - { - return string.Empty; - } - using (var writer = new StringWriter()) - { - var done = false; - var start = false; - while (!done) - { - try - { - var line = process.StandardOutput.ReadLine(); - MessageLogged?.Invoke(line); - if (line == null || line == startofDataToken) - { - start = true; - continue;//don't record start token to stream. - } - if (line == null || line == endOfDataToken) - { - done = true; - } - else - { //if we have started recieving valid data, start recording - if (!string.IsNullOrWhiteSpace(line) && start) - { - writer.WriteLine(line); - } - } - } - catch (Exception) - { - KillProcess(); - return GetCantCommunicateErrorMessage(); - } - } - - return writer.ToString(); - } - } - - protected void RaiseMessageLogged(string message) - { - MessageLogged?.Invoke(message); - } - - /// - /// Can't start Error message - /// - /// Returns error message - protected abstract string GetCantStartErrorMessage(); - - - /// - /// Can't communicate Error message - /// - /// Returns error message - protected abstract string GetCantCommunicateErrorMessage(); - - - - } /// /// Utilities for converting Markdown to html and for sanitizing html /// The Md2Html command line tool is used for doing the actual conversion/santizing @@ -175,6 +18,8 @@ protected void RaiseMessageLogged(string message) internal class Md2Html : CLIWrapper { private string relativePath = Path.Combine(@"Md2Html", @"Md2Html.exe"); + private int processCommunicationTimeoutms = 5000; + /// /// Constructor /// Start the CLI tool and keep it around @@ -228,9 +73,9 @@ internal string ParseMd2Html(string mdString, string mdPath) return GetCantCommunicateErrorMessage(); } - var output = GetData(); + var output = GetData(processCommunicationTimeoutms); - return output; + return output.Result; } /// @@ -257,9 +102,9 @@ internal string SanitizeHtml(string content) return GetCantCommunicateErrorMessage(); } - var output = GetData(); + var output = GetData(processCommunicationTimeoutms); - return output; + return output.Result; } /// diff --git a/src/DynamoUtilities/Properties/AssemblyInfo.cs b/src/DynamoUtilities/Properties/AssemblyInfo.cs index c3981334ac4..67a7633b408 100644 --- a/src/DynamoUtilities/Properties/AssemblyInfo.cs +++ b/src/DynamoUtilities/Properties/AssemblyInfo.cs @@ -24,3 +24,5 @@ [assembly: InternalsVisibleTo("DynamoApplications")] [assembly: InternalsVisibleTo("DynamoCLI")] [assembly: InternalsVisibleTo("NodeDocumentationMarkdownGenerator")] +[assembly: InternalsVisibleTo("DynamoUtilitiesTests")] + diff --git a/src/build.xml b/src/build.xml index 5212c9c9237..b2df74100c7 100644 --- a/src/build.xml +++ b/src/build.xml @@ -12,7 +12,7 @@ - Configuration=Release;Platform=$(Platform) + Configuration=Release;Platform=$(Platform);DotNet=$(DotNet) diff --git a/test/Directory.Build.props b/test/Directory.Build.props new file mode 100644 index 00000000000..5f7e4762f68 --- /dev/null +++ b/test/Directory.Build.props @@ -0,0 +1,5 @@ + + + true + + diff --git a/test/DynamoCoreTests/Logging/FeatureFlagTests.cs b/test/DynamoCoreTests/Logging/FeatureFlagTests.cs index 968d6b712a2..2200c56ecc8 100644 --- a/test/DynamoCoreTests/Logging/FeatureFlagTests.cs +++ b/test/DynamoCoreTests/Logging/FeatureFlagTests.cs @@ -1,7 +1,9 @@ using Dynamo.Utilities; using NUnit.Framework; +using NUnit.Framework.Internal; using System; using System.Diagnostics; +using System.Text.RegularExpressions; using System.Threading; namespace Dynamo.Tests.Logging @@ -69,6 +71,42 @@ public void FeatureFlagsShouldMessageLoggedShouldContainAllLogs() StringAssert.EndsWith("<<<<>>>>", log); } + //TODO(DYN-6464) Revisit this and log more when the logger is not easily overwhelmed. + [Test] + public void FeatureFlagsShouldMessageLoggedShouldOnlyContainNullFlagErrorOnce() + { + var testflagsManager = new DynamoUtilities.DynamoFeatureFlagsManager("testkey", new SynchronizationContext(), true); + testflagsManager.MessageLogged += TestflagsManager_MessageLogged; + testflagsManager.CheckFeatureFlag("TestFlag2", "na"); + testflagsManager.CheckFeatureFlag("TestFlag2", "na"); + testflagsManager.CheckFeatureFlag("TestFlag2", "na"); + testflagsManager.MessageLogged -= TestflagsManager_MessageLogged; + var matches = Regex.Matches(log, "wait longer for the cache").Count; + Assert.AreEqual(1,matches); + } + //TODO(DYN-6464) Revisit this and log more when the logger is not easily overwhelmed. + [Test] + public void FeatureFlagsShouldMessageLoggedShouldOnlyContainMissingFlagErrorOnce() + { + var testflagsManager = new DynamoUtilities.DynamoFeatureFlagsManager("testkey", new SynchronizationContext(), true); + testflagsManager.MessageLogged += TestflagsManager_MessageLogged; + testflagsManager.CacheAllFlags(); + testflagsManager.CheckFeatureFlag("MissingFlag", "na"); + testflagsManager.CheckFeatureFlag("MissingFlag", "na"); + testflagsManager.CheckFeatureFlag("MissingFlag", "na"); + testflagsManager.MessageLogged -= TestflagsManager_MessageLogged; + var matches = Regex.Matches(log, "failed to get value").Count; + Assert.AreEqual(1, matches); + } + [Test] + public void FeatureFlagsThrowsIfCheckIngNonSupportedType() + { + var testflagsManager = new DynamoUtilities.DynamoFeatureFlagsManager("testkey", new SynchronizationContext(), true); + Assert.Throws(() => + { + testflagsManager.CheckFeatureFlag("NumericTypeNotSupported", 10); + }); + } private void DynamoFeatureFlagsManager_FlagsRetrieved() { diff --git a/test/DynamoCoreWpfTests/PackageManager/PackageManagerViewExtensionTests.cs b/test/DynamoCoreWpfTests/PackageManager/PackageManagerViewExtensionTests.cs index 15787bb2fca..4aca8e5f17f 100644 --- a/test/DynamoCoreWpfTests/PackageManager/PackageManagerViewExtensionTests.cs +++ b/test/DynamoCoreWpfTests/PackageManager/PackageManagerViewExtensionTests.cs @@ -148,7 +148,7 @@ public void PackageManagerViewExtensionHasCorrectNumberOfRequestedExtensions() } [Test] - async public void LateLoadedViewExtensionsHaveMethodsCalled() + public void LateLoadedViewExtensionsHaveMethodsCalled() { var pkgviewExtension = View.viewExtensionManager.ViewExtensions.OfType().FirstOrDefault(); var pkgDir = Path.Combine(PackagesDirectory, "SampleViewExtension"); diff --git a/test/Libraries/DynamoUtilitiesTests/CLIWrapperTests.cs b/test/Libraries/DynamoUtilitiesTests/CLIWrapperTests.cs new file mode 100644 index 00000000000..0657e0b5a70 --- /dev/null +++ b/test/Libraries/DynamoUtilitiesTests/CLIWrapperTests.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; + +namespace DynamoUtilitiesTests +{ + [TestFixture] + public class CLIWrapperTests + { + /// + /// A test class that starts up the DynamoFF CLI and then kills it to cause a deadlock. + /// + private class HangingCLIWrapper: Dynamo.Utilities.CLIWrapper + { + private string relativePath = Path.Combine("DynamoFeatureFlags", "DynamoFeatureFlags.exe"); + protected override string GetCantStartErrorMessage() + { + throw new NotImplementedException(); + } + + protected override string GetCantCommunicateErrorMessage() + { + throw new NotImplementedException(); + } + internal HangingCLIWrapper() + { + StartProcess(relativePath, null); + } + + internal string GetData() + { + //wait a bit, and then kill the process + //this will cause GetData to hang and timeout. + Task.Run(() => + { System.Threading.Thread.Sleep(100); + process.Kill(); + }); + return GetData(2000).Result; + } + } + + [Test] + public void CLIWrapperDoesNotHangIfProcessDoesNotWriteToStdOut() + { + var sw = new System.Diagnostics.Stopwatch(); + sw.Start(); + var wrapper = new HangingCLIWrapper(); + Assert.AreEqual(string.Empty,wrapper.GetData()); + sw.Stop(); + Assert.GreaterOrEqual(sw.ElapsedMilliseconds,2000); + + } + } +} diff --git a/test/settings/DynamoSettings-NewSettings.xml b/test/settings/DynamoSettings-NewSettings.xml index 72e1d775195..4ae2b3afca4 100644 --- a/test/settings/DynamoSettings-NewSettings.xml +++ b/test/settings/DynamoSettings-NewSettings.xml @@ -74,6 +74,7 @@ true false false + true false true