From 9f48767aefc7f5bcc15f428e16f2deecff47f13c Mon Sep 17 00:00:00 2001 From: Efrey Kong Date: Wed, 19 Jan 2022 17:34:19 +0800 Subject: [PATCH] Add project files. --- LICENSE.MD | 201 ++ NoteWidget.sln | 51 + NoteWidgetAddIn/.editorconfig | 134 ++ NoteWidgetAddIn/AddIn.Ribbon.cs | 81 + NoteWidgetAddIn/AddIn.cs | 75 + NoteWidgetAddIn/CCOMStreamWrapper.cs | 110 + NoteWidgetAddIn/Export/AbstractExportor.cs | 115 + NoteWidgetAddIn/Export/CustomFileExportor.cs | 47 + NoteWidgetAddIn/Export/ExportFactory.cs | 42 + NoteWidgetAddIn/Export/ExportFormat.cs | 30 + NoteWidgetAddIn/Export/ExportHelper.cs | 50 + NoteWidgetAddIn/Export/HtmlExportor.cs | 50 + NoteWidgetAddIn/Export/IExportor.cs | 29 + NoteWidgetAddIn/Export/MarkdownExportor.cs | 41 + .../Export/OneNoteHostedExportor.cs | 30 + .../Extension/ColorSchemeExtension.cs | 59 + .../Markdown/Extension/DiagramExtension.cs | 37 + .../Markdown/Extension/HighlightExtension.cs | 49 + NoteWidgetAddIn/Markdown/HtmlTemplate.cs | 88 + .../Markdown/HtmlTemplateBuilder.cs | 68 + .../Markdown/ITemplateExtension.cs | 48 + NoteWidgetAddIn/Markdown/ITemplateRender.cs | 16 + NoteWidgetAddIn/Model/NodeType.cs | 19 + NoteWidgetAddIn/Model/NoteNode.cs | 180 ++ NoteWidgetAddIn/Model/NotePage.cs | 238 ++ NoteWidgetAddIn/Model/NotePageInfo.cs | 57 + NoteWidgetAddIn/NLog.config | 14 + NoteWidgetAddIn/NoteApplication.cs | 144 ++ NoteWidgetAddIn/NoteApplicationContext.cs | 39 + NoteWidgetAddIn/NoteWidgetAddIn.csproj | 280 +++ NoteWidgetAddIn/Properties/AssemblyInfo.cs | 42 + .../Properties/Resources.Designer.cs | 154 ++ NoteWidgetAddIn/Properties/Resources.resx | 145 ++ .../Properties/Settings.Designer.cs | 110 + NoteWidgetAddIn/Properties/Settings.settings | 27 + NoteWidgetAddIn/Properties/documents.ico | Bin 0 -> 1150 bytes NoteWidgetAddIn/Properties/markdown.png | Bin 0 -> 3796 bytes NoteWidgetAddIn/Properties/markdown_icon.ico | Bin 0 -> 112117 bytes NoteWidgetAddIn/Properties/markdownflag.png | Bin 0 -> 2872 bytes NoteWidgetAddIn/Properties/openfolder.png | Bin 0 -> 950 bytes NoteWidgetAddIn/Properties/ribbon.xml | 102 + NoteWidgetAddIn/Properties/setting.ico | Bin 0 -> 104093 bytes NoteWidgetAddIn/Properties/settings.png | Bin 0 -> 4642 bytes .../Resources/ImageResourceDictionary.xaml | 97 + .../Resources/MarkdownCheatSheet.html | 284 +++ .../Resources/css/github-markdown-dark.css | 8 + .../Resources/css/github-markdown-light.css | 8 + .../Resources/css/github-markdown.min.css | 8 + .../Resources/css/prism-coy.min.css | 1 + .../Resources/css/prism-dark.min.css | 1 + .../Resources/css/prism-funky.min.css | 1 + .../Resources/css/prism-okaidia.min.css | 1 + .../css/prism-solarizedlight.min.css | 1 + .../Resources/css/prism-tomorrow.min.css | 1 + .../Resources/css/prism-twilight.min.css | 1 + NoteWidgetAddIn/Resources/css/prism.css | 11 + NoteWidgetAddIn/Resources/js/mermaid.min.js | 3 + NoteWidgetAddIn/Resources/js/prism.js | 281 +++ .../AdvancedSettingsDialog.Designer.cs | 195 ++ .../Advanced/AdvancedSettingsDialog.cs | 92 + .../Advanced/AdvancedSettingsDialog.resx | 1860 +++++++++++++++ .../Advanced/WidgetAdvancedSettingsCommand.cs | 19 + NoteWidgetAddIn/RibbonCommand/Command.cs | 31 + .../RibbonCommand/CommandFactory.cs | 52 + .../Export/ExportToFileCommand.cs | 82 + .../Export/ExportToPathCommand.cs | 57 + .../Export/ExportToPathDialog.Designer.cs | 162 ++ .../Export/ExportToPathDialog.cs | 77 + .../Export/ExportToPathDialog.resx | 145 ++ .../Markdown/CheatsheetCommand.cs | 37 + .../Markdown/PreviewMarkdownCommand.cs | 77 + .../Markdown/WebBrowserWindow.xaml | 12 + .../Markdown/WebBrowserWindow.xaml.cs | 196 ++ .../RibbonCommand/WpfAddInApplication.cs | 85 + .../Utils/EnumDescriptionConverter.cs | 35 + NoteWidgetAddIn/Utils/ExceptionAssertion.cs | 18 + NoteWidgetAddIn/Utils/Extensions.cs | 225 ++ NoteWidgetAddIn/Utils/MarkdownHelper.cs | 31 + NoteWidgetAddIn/Utils/PathHelper.cs | 67 + .../Utils/RestrictedNodeTypeAttribute.cs | 25 + NoteWidgetAddIn/WidgetSettingsManager.cs | 49 + NoteWidgetAddIn/app.config | 33 + NoteWidgetAddIn/markdown128.png | Bin 0 -> 4687 bytes NoteWidgetAddIn/packages.config | 11 + .../NoteWidgetAddInSetup.vdproj | 2005 +++++++++++++++++ NoteWidgetTests/BaseDummyTest.cs | 32 + NoteWidgetTests/BaseInteropTest.cs | 20 + .../DummyData/NotebookHierarchy.xml | 43 + .../DummyData/NotebookHierarchy_Expected.xml | 23 + NoteWidgetTests/DummyData/PageHierarchy.xml | 1 + .../DummyData/SectionGroupHierarchy.xml | 9 + .../SectionGroupHierarchy_Expected.xml | 10 + .../DummyData/SectionHierarchy.xml | 4 + .../DummyData/SectionHierarchy_Expected.xml | 5 + NoteWidgetTests/DummyData/TaggedPage.xml | 477 ++++ ...6248993555224420161066687775526316971}.xml | 31 + ...4442055462406520137364240064103627971}.xml | 39 + ...0608983392449520151492106384070007221}.xml | 33 + ...4550601460158520165992657368372596901}.xml | 39 + ...8395446988629731972422109116520132061}.xml | 30 + ...3573282337301011917182284793899649511}.xml | 36 + NoteWidgetTests/DummyDataExportTest.cs | 107 + NoteWidgetTests/DummyImpl/DummyApplication.cs | 166 ++ NoteWidgetTests/DummyImpl/DummyWindow.cs | 75 + NoteWidgetTests/DummyImpl/DummyWindows.cs | 35 + NoteWidgetTests/InteropExportTest.cs | 91 + NoteWidgetTests/MarkdownTest.cs | 58 + NoteWidgetTests/NoteApplicationTest.cs | 114 + NoteWidgetTests/NoteWidgetTests.csproj | 104 + .../Properties/Resources.Designer.cs | 73 + NoteWidgetTests/Properties/Resources.resx | 124 + NoteWidgetTests/Properties/markdown128.png | Bin 0 -> 4665 bytes NoteWidgetTests/UtilTests.cs | 33 + NoteWidgetTests/Utils/DummyData.cs | 54 + README.MD | 83 + cheatsheet_snapshot.png | Bin 0 -> 103186 bytes powershell-copyfile-runas.bat | 5 + preview_snapshot.png | Bin 0 -> 167034 bytes template.html | 0 119 files changed, 11341 insertions(+) create mode 100644 LICENSE.MD create mode 100644 NoteWidget.sln create mode 100644 NoteWidgetAddIn/.editorconfig create mode 100644 NoteWidgetAddIn/AddIn.Ribbon.cs create mode 100644 NoteWidgetAddIn/AddIn.cs create mode 100644 NoteWidgetAddIn/CCOMStreamWrapper.cs create mode 100644 NoteWidgetAddIn/Export/AbstractExportor.cs create mode 100644 NoteWidgetAddIn/Export/CustomFileExportor.cs create mode 100644 NoteWidgetAddIn/Export/ExportFactory.cs create mode 100644 NoteWidgetAddIn/Export/ExportFormat.cs create mode 100644 NoteWidgetAddIn/Export/ExportHelper.cs create mode 100644 NoteWidgetAddIn/Export/HtmlExportor.cs create mode 100644 NoteWidgetAddIn/Export/IExportor.cs create mode 100644 NoteWidgetAddIn/Export/MarkdownExportor.cs create mode 100644 NoteWidgetAddIn/Export/OneNoteHostedExportor.cs create mode 100644 NoteWidgetAddIn/Markdown/Extension/ColorSchemeExtension.cs create mode 100644 NoteWidgetAddIn/Markdown/Extension/DiagramExtension.cs create mode 100644 NoteWidgetAddIn/Markdown/Extension/HighlightExtension.cs create mode 100644 NoteWidgetAddIn/Markdown/HtmlTemplate.cs create mode 100644 NoteWidgetAddIn/Markdown/HtmlTemplateBuilder.cs create mode 100644 NoteWidgetAddIn/Markdown/ITemplateExtension.cs create mode 100644 NoteWidgetAddIn/Markdown/ITemplateRender.cs create mode 100644 NoteWidgetAddIn/Model/NodeType.cs create mode 100644 NoteWidgetAddIn/Model/NoteNode.cs create mode 100644 NoteWidgetAddIn/Model/NotePage.cs create mode 100644 NoteWidgetAddIn/Model/NotePageInfo.cs create mode 100644 NoteWidgetAddIn/NLog.config create mode 100644 NoteWidgetAddIn/NoteApplication.cs create mode 100644 NoteWidgetAddIn/NoteApplicationContext.cs create mode 100644 NoteWidgetAddIn/NoteWidgetAddIn.csproj create mode 100644 NoteWidgetAddIn/Properties/AssemblyInfo.cs create mode 100644 NoteWidgetAddIn/Properties/Resources.Designer.cs create mode 100644 NoteWidgetAddIn/Properties/Resources.resx create mode 100644 NoteWidgetAddIn/Properties/Settings.Designer.cs create mode 100644 NoteWidgetAddIn/Properties/Settings.settings create mode 100644 NoteWidgetAddIn/Properties/documents.ico create mode 100644 NoteWidgetAddIn/Properties/markdown.png create mode 100644 NoteWidgetAddIn/Properties/markdown_icon.ico create mode 100644 NoteWidgetAddIn/Properties/markdownflag.png create mode 100644 NoteWidgetAddIn/Properties/openfolder.png create mode 100644 NoteWidgetAddIn/Properties/ribbon.xml create mode 100644 NoteWidgetAddIn/Properties/setting.ico create mode 100644 NoteWidgetAddIn/Properties/settings.png create mode 100644 NoteWidgetAddIn/Resources/ImageResourceDictionary.xaml create mode 100644 NoteWidgetAddIn/Resources/MarkdownCheatSheet.html create mode 100644 NoteWidgetAddIn/Resources/css/github-markdown-dark.css create mode 100644 NoteWidgetAddIn/Resources/css/github-markdown-light.css create mode 100644 NoteWidgetAddIn/Resources/css/github-markdown.min.css create mode 100644 NoteWidgetAddIn/Resources/css/prism-coy.min.css create mode 100644 NoteWidgetAddIn/Resources/css/prism-dark.min.css create mode 100644 NoteWidgetAddIn/Resources/css/prism-funky.min.css create mode 100644 NoteWidgetAddIn/Resources/css/prism-okaidia.min.css create mode 100644 NoteWidgetAddIn/Resources/css/prism-solarizedlight.min.css create mode 100644 NoteWidgetAddIn/Resources/css/prism-tomorrow.min.css create mode 100644 NoteWidgetAddIn/Resources/css/prism-twilight.min.css create mode 100644 NoteWidgetAddIn/Resources/css/prism.css create mode 100644 NoteWidgetAddIn/Resources/js/mermaid.min.js create mode 100644 NoteWidgetAddIn/Resources/js/prism.js create mode 100644 NoteWidgetAddIn/RibbonCommand/Advanced/AdvancedSettingsDialog.Designer.cs create mode 100644 NoteWidgetAddIn/RibbonCommand/Advanced/AdvancedSettingsDialog.cs create mode 100644 NoteWidgetAddIn/RibbonCommand/Advanced/AdvancedSettingsDialog.resx create mode 100644 NoteWidgetAddIn/RibbonCommand/Advanced/WidgetAdvancedSettingsCommand.cs create mode 100644 NoteWidgetAddIn/RibbonCommand/Command.cs create mode 100644 NoteWidgetAddIn/RibbonCommand/CommandFactory.cs create mode 100644 NoteWidgetAddIn/RibbonCommand/Export/ExportToFileCommand.cs create mode 100644 NoteWidgetAddIn/RibbonCommand/Export/ExportToPathCommand.cs create mode 100644 NoteWidgetAddIn/RibbonCommand/Export/ExportToPathDialog.Designer.cs create mode 100644 NoteWidgetAddIn/RibbonCommand/Export/ExportToPathDialog.cs create mode 100644 NoteWidgetAddIn/RibbonCommand/Export/ExportToPathDialog.resx create mode 100644 NoteWidgetAddIn/RibbonCommand/Markdown/CheatsheetCommand.cs create mode 100644 NoteWidgetAddIn/RibbonCommand/Markdown/PreviewMarkdownCommand.cs create mode 100644 NoteWidgetAddIn/RibbonCommand/Markdown/WebBrowserWindow.xaml create mode 100644 NoteWidgetAddIn/RibbonCommand/Markdown/WebBrowserWindow.xaml.cs create mode 100644 NoteWidgetAddIn/RibbonCommand/WpfAddInApplication.cs create mode 100644 NoteWidgetAddIn/Utils/EnumDescriptionConverter.cs create mode 100644 NoteWidgetAddIn/Utils/ExceptionAssertion.cs create mode 100644 NoteWidgetAddIn/Utils/Extensions.cs create mode 100644 NoteWidgetAddIn/Utils/MarkdownHelper.cs create mode 100644 NoteWidgetAddIn/Utils/PathHelper.cs create mode 100644 NoteWidgetAddIn/Utils/RestrictedNodeTypeAttribute.cs create mode 100644 NoteWidgetAddIn/WidgetSettingsManager.cs create mode 100644 NoteWidgetAddIn/app.config create mode 100644 NoteWidgetAddIn/markdown128.png create mode 100644 NoteWidgetAddIn/packages.config create mode 100644 NoteWidgetAddInSetup/NoteWidgetAddInSetup.vdproj create mode 100644 NoteWidgetTests/BaseDummyTest.cs create mode 100644 NoteWidgetTests/BaseInteropTest.cs create mode 100644 NoteWidgetTests/DummyData/NotebookHierarchy.xml create mode 100644 NoteWidgetTests/DummyData/NotebookHierarchy_Expected.xml create mode 100644 NoteWidgetTests/DummyData/PageHierarchy.xml create mode 100644 NoteWidgetTests/DummyData/SectionGroupHierarchy.xml create mode 100644 NoteWidgetTests/DummyData/SectionGroupHierarchy_Expected.xml create mode 100644 NoteWidgetTests/DummyData/SectionHierarchy.xml create mode 100644 NoteWidgetTests/DummyData/SectionHierarchy_Expected.xml create mode 100644 NoteWidgetTests/DummyData/TaggedPage.xml create mode 100644 NoteWidgetTests/DummyData/{443F89FE-0C2F-41D2-8FCA-B54E1F45349B}{1}{E19524986248993555224420161066687775526316971}.xml create mode 100644 NoteWidgetTests/DummyData/{443F89FE-0C2F-41D2-8FCA-B54E1F45349B}{1}{E19554024442055462406520137364240064103627971}.xml create mode 100644 NoteWidgetTests/DummyData/{5E3A0919-1331-41D5-B19C-4AE7F96D7626}{1}{E19529340608983392449520151492106384070007221}.xml create mode 100644 NoteWidgetTests/DummyData/{842240F6-F77A-4421-B2F6-44510E03ABAB}{1}{E19483954550601460158520165992657368372596901}.xml create mode 100644 NoteWidgetTests/DummyData/{9CA0EF3E-A634-41E8-A1B7-821A01E657E2}{1}{E1949968395446988629731972422109116520132061}.xml create mode 100644 NoteWidgetTests/DummyData/{B75B0FB1-6DB5-4ED2-9C69-4060F8FB7FF8}{1}{E1954863573282337301011917182284793899649511}.xml create mode 100644 NoteWidgetTests/DummyDataExportTest.cs create mode 100644 NoteWidgetTests/DummyImpl/DummyApplication.cs create mode 100644 NoteWidgetTests/DummyImpl/DummyWindow.cs create mode 100644 NoteWidgetTests/DummyImpl/DummyWindows.cs create mode 100644 NoteWidgetTests/InteropExportTest.cs create mode 100644 NoteWidgetTests/MarkdownTest.cs create mode 100644 NoteWidgetTests/NoteApplicationTest.cs create mode 100644 NoteWidgetTests/NoteWidgetTests.csproj create mode 100644 NoteWidgetTests/Properties/Resources.Designer.cs create mode 100644 NoteWidgetTests/Properties/Resources.resx create mode 100644 NoteWidgetTests/Properties/markdown128.png create mode 100644 NoteWidgetTests/UtilTests.cs create mode 100644 NoteWidgetTests/Utils/DummyData.cs create mode 100644 README.MD create mode 100644 cheatsheet_snapshot.png create mode 100644 powershell-copyfile-runas.bat create mode 100644 preview_snapshot.png create mode 100644 template.html diff --git a/LICENSE.MD b/LICENSE.MD new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE.MD @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/NoteWidget.sln b/NoteWidget.sln new file mode 100644 index 0000000..8bc5c3b --- /dev/null +++ b/NoteWidget.sln @@ -0,0 +1,51 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31919.166 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NoteWidgetTests", "NoteWidgetTests\NoteWidgetTests.csproj", "{FB85C7C6-5DB7-4EFB-9BC4-AFFF33C1E3EA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoteWidgetAddIn", "NoteWidgetAddIn\NoteWidgetAddIn.csproj", "{280104F5-13BA-4193-BFF5-5A5C48261640}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{732EB35D-6A00-4E3C-B1AF-2A7A0ABF10D2}" + ProjectSection(SolutionItems) = preProject + cheatsheet_snapshot.png = cheatsheet_snapshot.png + LICENSE.MD = LICENSE.MD + powershell-copyfile-runas.bat = powershell-copyfile-runas.bat + preview_snapshot.png = preview_snapshot.png + README.MD = README.MD + EndProjectSection +EndProject +Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "NoteWidgetAddIn.Setup", "NoteWidgetAddInSetup\NoteWidgetAddInSetup.vdproj", "{1D540207-035C-40B7-BD5B-48FF023152C2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Publish|Any CPU = Publish|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FB85C7C6-5DB7-4EFB-9BC4-AFFF33C1E3EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB85C7C6-5DB7-4EFB-9BC4-AFFF33C1E3EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB85C7C6-5DB7-4EFB-9BC4-AFFF33C1E3EA}.Publish|Any CPU.ActiveCfg = Publish|Any CPU + {FB85C7C6-5DB7-4EFB-9BC4-AFFF33C1E3EA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB85C7C6-5DB7-4EFB-9BC4-AFFF33C1E3EA}.Release|Any CPU.Build.0 = Release|Any CPU + {280104F5-13BA-4193-BFF5-5A5C48261640}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {280104F5-13BA-4193-BFF5-5A5C48261640}.Debug|Any CPU.Build.0 = Debug|Any CPU + {280104F5-13BA-4193-BFF5-5A5C48261640}.Publish|Any CPU.ActiveCfg = Publish|Any CPU + {280104F5-13BA-4193-BFF5-5A5C48261640}.Publish|Any CPU.Build.0 = Publish|Any CPU + {280104F5-13BA-4193-BFF5-5A5C48261640}.Release|Any CPU.ActiveCfg = Release|Any CPU + {280104F5-13BA-4193-BFF5-5A5C48261640}.Release|Any CPU.Build.0 = Release|Any CPU + {1D540207-035C-40B7-BD5B-48FF023152C2}.Debug|Any CPU.ActiveCfg = Debug + {1D540207-035C-40B7-BD5B-48FF023152C2}.Debug|Any CPU.Build.0 = Debug + {1D540207-035C-40B7-BD5B-48FF023152C2}.Publish|Any CPU.ActiveCfg = Publish + {1D540207-035C-40B7-BD5B-48FF023152C2}.Release|Any CPU.ActiveCfg = Release + {1D540207-035C-40B7-BD5B-48FF023152C2}.Release|Any CPU.Build.0 = Release + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6124B423-3309-464C-A107-BD5DD68ED3A3} + EndGlobalSection +EndGlobal diff --git a/NoteWidgetAddIn/.editorconfig b/NoteWidgetAddIn/.editorconfig new file mode 100644 index 0000000..370b77b --- /dev/null +++ b/NoteWidgetAddIn/.editorconfig @@ -0,0 +1,134 @@ +# To learn more about .editorconfig see https://aka.ms/editorconfigdocs +############################### +# Core EditorConfig Options # +############################### +root = true +# All files +[*] +indent_style = space + +# XML project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# XML config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# Code files +[*.{cs,csx,vb,vbx}] +indent_size = 4 +insert_final_newline = true +charset = utf-8-bom +file_header_template = Copyright (c) Efrey Kong. All Rights Reserved.\nLicensed under the Apache License, Version 2.0. +############################### +# .NET Coding Conventions # +############################### +[*.{cs,vb}] +# Organize usings +dotnet_sort_system_directives_first = true +# this. preferences +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_readonly_field = true:suggestion +# Expression-level preferences +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +############################### +# Naming Conventions # +############################### +# Style Definitions +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const +############################### +# C# Coding Conventions # +############################### +[*.cs] +# var preferences +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent +csharp_style_var_elsewhere = true:silent +# Expression-bodied members +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +# Pattern matching preferences +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +# Null-checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion +# Expression-level preferences +csharp_prefer_braces = true:silent +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +############################### +# C# Formatting Rules # +############################### +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true +# Indentation preferences +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left +# Space preferences +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +# Wrapping preferences +csharp_preserve_single_line_statements = true +csharp_preserve_single_line_blocks = true +############################### +# VB Coding Conventions # +############################### +[*.vb] +# Modifier preferences +visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion diff --git a/NoteWidgetAddIn/AddIn.Ribbon.cs b/NoteWidgetAddIn/AddIn.Ribbon.cs new file mode 100644 index 0000000..e745489 --- /dev/null +++ b/NoteWidgetAddIn/AddIn.Ribbon.cs @@ -0,0 +1,81 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices.ComTypes; +using System.Threading.Tasks; +using Microsoft.Office.Core; +using NoteWidgetAddIn.RibbonCommand; + +#pragma warning disable CS3001 // Argument type is not CLS-compliant +namespace NoteWidgetAddIn +{ + public partial class AddIn : IRibbonExtensibility + { + + #region implements IRibbonExtensibility + /// + /// Gets the defined ribbon tab xml string content + /// This method is triggered after OnAddInsUpdate + /// + /// + /// The xml string content which customized ribbon menu items + public string GetCustomUI(string RibbonID) + { + return Properties.Resources.ribbon; + } + #endregion + + #region Custom Ribbon methods + public IStream GetImage(string imageName) + { + var ms = new MemoryStream(); + BindingFlags flags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + var b = typeof(Properties.Resources).GetProperty(Path.GetFileNameWithoutExtension(imageName), flags).GetValue(null, null) as Bitmap; + b.Save(ms, ImageFormat.Png); + return new CCOMStreamWrapper(ms); + } + + #endregion + + #region Ribbon Action Commands + /// + /// Export to file + /// + /// + /// + public async Task ExportFileCmd(IRibbonControl control) => await _commandFactory.Run(control.Tag); + + /// + /// Export to hierarchical files + /// + /// + /// + public async Task ExportPathCmd(IRibbonControl control) => await _commandFactory.Run(control.Tag, control.Context); + + /// + /// View current page's markdown content as Html in a new window. + /// + /// + /// + public async Task PreviewMarkdownCmd(IRibbonControl control) => await _commandFactory.Run(); + /// + /// Show markdown cheat sheet window + /// + /// + /// + public async Task MarkdownCheatsheetCmd(IRibbonControl control) => await _commandFactory.Run(); + /// + /// Show advanced settings window + /// + /// + /// + public async Task WidgetAdvancedSettingsCmd(IRibbonControl control) => await _commandFactory.Run(); + + #endregion + } +} diff --git a/NoteWidgetAddIn/AddIn.cs b/NoteWidgetAddIn/AddIn.cs new file mode 100644 index 0000000..2abcb53 --- /dev/null +++ b/NoteWidgetAddIn/AddIn.cs @@ -0,0 +1,75 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using Extensibility; +using NLog; +using NoteWidgetAddIn.RibbonCommand; + +#pragma warning disable CS3008 // Type is not CLS-compliant +#pragma warning disable CS3003 // Type is not CLS-compliant +#pragma warning disable CS3001 // Type is not CLS-compliant +namespace NoteWidgetAddIn +{ + [ComVisible(true)] + [Guid("EEE896F2-39B1-4D71-8A54-3EFDFB48BB06"), ProgId("NoteWidget.AddIn")] + public partial class AddIn : IDTExtensibility2 + { + private static readonly ILogger _logger = LogManager.GetCurrentClassLogger(); + private CommandFactory _commandFactory; + static AddIn() + { + var nlogConfigPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "NLog.config"); + LogManager.Configuration = new NLog.Config.XmlLoggingConfiguration(nlogConfigPath); + } + + public void OnConnection(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom) + { + //OneNote window is not ready to use. + _logger.Debug("OnConnection"); + WpfAddInApplication.Current = new WpfAddInApplication(); + } + + public void OnDisconnection(ext_DisconnectMode RemoveMode, ref Array custom) + { + GC.Collect(); + //GC.WaitForPendingFinalizers(); + Environment.Exit(0); + } + + public void OnAddInsUpdate(ref Array custom) + { + } + + public void OnStartupComplete(ref Array custom) + { + //Leave factory instainced here, since from now on OneNote Window is ready to access. + try + { + NoteApplicationContext context = new NoteApplicationContext(); + _commandFactory = new CommandFactory(context); + } + catch (Exception ex) + { + _logger.Error(ex); + } + } + + public void OnBeginShutdown(ref Array custom) + { + _logger.Debug("OnBeginShutdown"); + try + { + _commandFactory = null; + WpfAddInApplication.Current.Shutdown(); + } + catch(Exception ex) + { + _logger.Error(ex); + } + } + } +} diff --git a/NoteWidgetAddIn/CCOMStreamWrapper.cs b/NoteWidgetAddIn/CCOMStreamWrapper.cs new file mode 100644 index 0000000..6d8fdf4 --- /dev/null +++ b/NoteWidgetAddIn/CCOMStreamWrapper.cs @@ -0,0 +1,110 @@ +/* + * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. + */ + +using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; + +namespace NoteWidgetAddIn +{ + class CCOMStreamWrapper : IStream + { + public CCOMStreamWrapper(System.IO.Stream streamWrap) + { + m_stream = streamWrap; + } + + public void Clone(out IStream ppstm) + { + ppstm = new CCOMStreamWrapper(m_stream); + } + + public void Commit(int grfCommitFlags) + { + m_stream.Flush(); + } + + public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten) + { + } + + public void LockRegion(long libOffset, long cb, int dwLockType) + { + throw new System.NotImplementedException(); + } + + public void Read(byte[] pv, int cb, IntPtr pcbRead) + { + Marshal.WriteInt64(pcbRead, m_stream.Read(pv, 0, cb)); + } + + public void Revert() + { + throw new System.NotImplementedException(); + } + + public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition) + { + long posMoveTo = 0; + Marshal.WriteInt64(plibNewPosition, m_stream.Position); + switch (dwOrigin) + { + case 0: + { + /* STREAM_SEEK_SET */ + posMoveTo = dlibMove; + } + break; + case 1: + { + /* STREAM_SEEK_CUR */ + posMoveTo = m_stream.Position + dlibMove; + + } + break; + case 2: + { + /* STREAM_SEEK_END */ + posMoveTo = m_stream.Length + dlibMove; + } + break; + default: + return; + } + if (posMoveTo >= 0 && posMoveTo < m_stream.Length) + { + m_stream.Position = posMoveTo; + Marshal.WriteInt64(plibNewPosition, m_stream.Position); + } + } + + public void SetSize(long libNewSize) + { + m_stream.SetLength(libNewSize); + } + + public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag) + { + pstatstg = new System.Runtime.InteropServices.ComTypes.STATSTG(); + pstatstg.cbSize = m_stream.Length; + if ((grfStatFlag & 0x0001/* STATFLAG_NONAME */) != 0) + return; + pstatstg.pwcsName = m_stream.ToString(); + } + + public void UnlockRegion(long libOffset, long cb, int dwLockType) + { + throw new System.NotImplementedException(); + } + + public void Write(byte[] pv, int cb, IntPtr pcbWritten) + { + Marshal.WriteInt64(pcbWritten, 0); + m_stream.Write(pv, 0, cb); + Marshal.WriteInt64(pcbWritten, cb); + } + + private System.IO.Stream m_stream; + } +} diff --git a/NoteWidgetAddIn/Export/AbstractExportor.cs b/NoteWidgetAddIn/Export/AbstractExportor.cs new file mode 100644 index 0000000..28cb62d --- /dev/null +++ b/NoteWidgetAddIn/Export/AbstractExportor.cs @@ -0,0 +1,115 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.IO; +using System.Text; +using NoteWidgetAddIn.Model; + +namespace NoteWidgetAddIn.Export +{ + internal abstract class AbstractExportor : IExportor + { + private NoteApplicationContext _context; + public AbstractExportor(ExportFormat fileFormat) + { + FileFormat = fileFormat; + } + public ExportFormat FileFormat { get; private set; } + protected NoteApplication NoteApp { get; private set; } + + public string FileExtension + { + get + { + return ExportHelper.GetExportFormatFileExtension(FileFormat); + } + } + public void SetContext(NoteApplicationContext context) + { + _context = context; + NoteApp = _context.CreateApplication(); + } + + public abstract void ExportNodeToSingleFile(string nodeID, string filePath); + + protected abstract void CreatePageFile(string pageID, string file); + + public virtual string ExportNodeToHierarchicalFiles(string nodeID, string exportPath, bool createsHierarchicalFolder = true) + { + ExceptionAssertion.ThrowArgumentNullExceptionIfNull(nodeID, nameof(nodeID)); + + if (createsHierarchicalFolder) + { + var rootNode = NoteApp.GetNoteNodeHierarchy(nodeID); + if (rootNode != null) + { + return ExportFileHierarchyRecursively(rootNode, exportPath); + } + return null; + } + else + { + string rootPath; + var rootNode = NoteApp.GetNoteNodeHierarchy(nodeID); + if (rootNode != null) + { + var folderName = $"OneNote_{rootNode.Name}_{DateTime.Now.ToString("yyyyMMddHHmmss")}"; + rootPath = PathHelper.MakeUniqueFolderName(Path.Combine(exportPath, folderName)); + Directory.CreateDirectory(rootPath); + foreach (var node in rootNode.Descendants(n => n.NodeType == NodeType.Page)) + { + var filePath = Path.Combine(rootPath, GetFullPathNodeName(node, '_') + FileExtension); + CreatePageFile(node.ID, filePath); + } + return rootPath; + } + return null; + } + } + + private string ExportFileHierarchyRecursively(NoteNode parentNode, string hierarchyFolderPath) + { + if (parentNode.NodeType == NodeType.Page) + { + var file = Path.Combine(hierarchyFolderPath, parentNode.Name + FileExtension); + CreatePageFile(parentNode.ID, file); + } + string currentFolderPath; + if (parentNode.NodeType != NodeType.Page || (parentNode.NodeType == NodeType.Page && parentNode.Children.Count > 0)) + { + currentFolderPath = PathHelper.MakeUniqueFolderName(Path.Combine(hierarchyFolderPath, parentNode.Name)); + Directory.CreateDirectory(currentFolderPath); + } + else + { + currentFolderPath = hierarchyFolderPath; + } + foreach (var childNode in parentNode.Children) + { + ExportFileHierarchyRecursively(childNode, currentFolderPath); + } + + return currentFolderPath; + } + + protected string GetFullPathNodeName(NoteNode node, char seperatorChar) + { + var fileNameBuilder = new StringBuilder(); + NoteNode tmp = node; + while (tmp != null) + { + if (fileNameBuilder.Length == 0) + { + fileNameBuilder.Append(tmp.Name); + } + else + { + fileNameBuilder.Insert(0, tmp.Name + seperatorChar.ToString()); + } + tmp = tmp.Parent; + } + return fileNameBuilder.ToString(); + } + } +} diff --git a/NoteWidgetAddIn/Export/CustomFileExportor.cs b/NoteWidgetAddIn/Export/CustomFileExportor.cs new file mode 100644 index 0000000..d968d43 --- /dev/null +++ b/NoteWidgetAddIn/Export/CustomFileExportor.cs @@ -0,0 +1,47 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.IO; +using NoteWidgetAddIn.Model; + +namespace NoteWidgetAddIn.Export +{ + internal abstract class CustomFileExportor : AbstractExportor + { + protected CustomFileExportor(ExportFormat fileFormat) : base(fileFormat) { } + public override void ExportNodeToSingleFile(string nodeID, string filePath) + { + ExceptionAssertion.ThrowArgumentNullExceptionIfNull(nodeID, nameof(nodeID)); + ExceptionAssertion.ThrowArgumentNullExceptionIfNull(filePath, nameof(filePath)); + + var rootNode = NoteApp.GetNoteNodeHierarchy(nodeID); + if (rootNode != null) + { + using (var writer = BeginCreateFile(filePath)) + { + foreach (var node in rootNode.Descendants(n => n.NodeType == NodeType.Page)) + { + WriteFileContent(writer, NoteApp.GetNotePage(node.ID), GetFullPathNodeName(node, '\\')); + } + EndCreateFile(writer); + } + } + } + + protected override void CreatePageFile(string pageID, string file) + { + var page = NoteApp.GetNotePage(pageID); + using (var writer = BeginCreateFile(file)) + { + WriteFileContent(writer, page); + EndCreateFile(writer); + } + } + + protected abstract StreamWriter BeginCreateFile(string file); + protected abstract void WriteFileContent(StreamWriter writer, NotePage page, string title = null); + protected abstract void EndCreateFile(StreamWriter writer); + } +} diff --git a/NoteWidgetAddIn/Export/ExportFactory.cs b/NoteWidgetAddIn/Export/ExportFactory.cs new file mode 100644 index 0000000..f816300 --- /dev/null +++ b/NoteWidgetAddIn/Export/ExportFactory.cs @@ -0,0 +1,42 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.IO; +using System.Text; +using System.Xml.Linq; +using Microsoft.Office.Interop.OneNote; +using NoteWidgetAddIn.Export; +using NoteWidgetAddIn.Model; + +namespace NoteWidgetAddIn +{ + public class ExportFactory + { + /// + /// Creates an instance from IExportor + /// + /// + /// + /// + public static IExportor CreateExportor(NoteApplicationContext context,ExportFormat format) + { + IExportor exportor; + if (format == ExportFormat.Markdown) + { + exportor = new MarkdownExportor(format); + } + else if (format == ExportFormat.Html) + { + exportor = new HtmlExportor(format); + } + else + { + exportor = new OneNoteHostedExporter(format); + } + exportor.SetContext(context); + + return exportor; + } + } +} diff --git a/NoteWidgetAddIn/Export/ExportFormat.cs b/NoteWidgetAddIn/Export/ExportFormat.cs new file mode 100644 index 0000000..d7e7860 --- /dev/null +++ b/NoteWidgetAddIn/Export/ExportFormat.cs @@ -0,0 +1,30 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System.ComponentModel; +using Microsoft.Office.Interop.OneNote; +using NoteWidgetAddIn.Model; + +#pragma warning disable CS3016 +namespace NoteWidgetAddIn +{ + public enum ExportFormat + { + [Description("PDF(*.pdf)")] + [RestrictedNodeType(NodeType.Notebook, NodeType.Section, NodeType.Page)] + PDF = PublishFormat.pfPDF, + [Description("XPS Document(*.xps)")] + [RestrictedNodeType(NodeType.Notebook, NodeType.Section, NodeType.Page)] + XPS = PublishFormat.pfXPS, + [Description("Single File Web Page(*.mht)")] + [RestrictedNodeType(NodeType.Section)] + MHTML = PublishFormat.pfMHTML, + [Description("Microsoft Word XML Document(*.docx)")] + [RestrictedNodeType(NodeType.Section)] + Word = PublishFormat.pfWord, + [Description("Markdown Document(*.md)")] + Markdown = 100, + [Description("Html Document from markdown(*.html)")] + Html = 101 + } +} diff --git a/NoteWidgetAddIn/Export/ExportHelper.cs b/NoteWidgetAddIn/Export/ExportHelper.cs new file mode 100644 index 0000000..7eee796 --- /dev/null +++ b/NoteWidgetAddIn/Export/ExportHelper.cs @@ -0,0 +1,50 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using NoteWidgetAddIn.Model; + +namespace NoteWidgetAddIn +{ + public class ExportHelper + { + private static IDictionary dictAvailableFormats = new Dictionary(); + public static ExportFormat[] GetAvailableExportFormats(NodeType nodeType) + { + if (!dictAvailableFormats.ContainsKey(nodeType)) + { + var result = new List(); + foreach (var e in (ExportFormat[])Enum.GetValues(typeof(ExportFormat))) + { + var restricted = e.GetRestrictedNodeTypes(); + if (restricted.Length == 0 || (e.GetRestrictedNodeTypes().Contains(nodeType))) + { + result.Add(e); + } + } + dictAvailableFormats.Add(nodeType, result.ToArray()); + } + return dictAvailableFormats[nodeType]; + } + + public static string GetExportFormatExtPattern(ExportFormat format) + { + var desc = format.GetDescription(); + var match = Regex.Match(desc, @"\(([^)]*)\)"); + if (match.Success) + { + return match.Groups[1].Value; + } + throw new InvalidOperationException($"No extension described in {format.GetType()}.{format}"); + } + + public static string GetExportFormatFileExtension(ExportFormat format) + { + return Path.GetExtension(GetExportFormatExtPattern(format)); + } + } +} diff --git a/NoteWidgetAddIn/Export/HtmlExportor.cs b/NoteWidgetAddIn/Export/HtmlExportor.cs new file mode 100644 index 0000000..c99c7c7 --- /dev/null +++ b/NoteWidgetAddIn/Export/HtmlExportor.cs @@ -0,0 +1,50 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using NoteWidgetAddIn.Markdown; +using NoteWidgetAddIn.Model; + +namespace NoteWidgetAddIn.Export +{ + internal class HtmlExportor : CustomFileExportor + { + public HtmlExportor(ExportFormat fileFormat) : base(fileFormat) + { + + } + protected override StreamWriter BeginCreateFile(string file) + { + var writer = File.CreateText(file); + var title = Path.GetFileNameWithoutExtension(file); + var header = HtmlTemplate.OnlineResourceTemplate.ToHead(title); + writer.WriteLine(header); + writer.Flush(); + return writer; + } + protected override void WriteFileContent(StreamWriter writer, NotePage page, string title = null) + { + if (!string.IsNullOrEmpty(title)) + { + writer.WriteLine("
"); + writer.WriteLine($"

{title}

"); + writer.WriteLine("
"); + } + writer.WriteLine(MarkdownHelper.MarkdownToHtml(page.ContentInnerText)); + writer.WriteLine("

"); + writer.Flush(); + } + + protected override void EndCreateFile(StreamWriter writer) + { + writer.WriteLine(HtmlTemplate.OnlineResourceTemplate.ToFoot()); + writer.Flush(); + } + } +} diff --git a/NoteWidgetAddIn/Export/IExportor.cs b/NoteWidgetAddIn/Export/IExportor.cs new file mode 100644 index 0000000..c9ec93c --- /dev/null +++ b/NoteWidgetAddIn/Export/IExportor.cs @@ -0,0 +1,29 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +namespace NoteWidgetAddIn +{ + public interface IExportor + { + void SetContext(NoteApplicationContext context); + /// + /// Gets export file format + /// + ExportFormat FileFormat { get; } + /// + /// Export all OneNote pages under specified node to a single file. + /// + /// A Notebook, Section Group, Section or Page ID + /// File name with absolute path + /// the file name of created single file. + void ExportNodeToSingleFile(string nodeID, string filePath); + /// + /// Export OneNote pages under specified node, Each page a file. + /// + /// A Notebook, Section Group, Section or Page ID + /// A absolute path which export file(s) will be created to + /// Creates folder for each Notebook/Section Group/Section + /// the path contains exported files + string ExportNodeToHierarchicalFiles(string nodeID, string exportPath, bool createsHierarchicalFolder = true); + } +} diff --git a/NoteWidgetAddIn/Export/MarkdownExportor.cs b/NoteWidgetAddIn/Export/MarkdownExportor.cs new file mode 100644 index 0000000..97a8fba --- /dev/null +++ b/NoteWidgetAddIn/Export/MarkdownExportor.cs @@ -0,0 +1,41 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using NoteWidgetAddIn.Model; + +namespace NoteWidgetAddIn.Export +{ + internal class MarkdownExportor : CustomFileExportor + { + public MarkdownExportor(ExportFormat fileFormat) : base(fileFormat) {} + + protected override StreamWriter BeginCreateFile(string file) + { + return File.CreateText(file); + } + protected override void WriteFileContent(StreamWriter writer, NotePage page, string title = null) + { + if (!string.IsNullOrEmpty(title)) + { + writer.WriteLine(new String('-', 50) + " "); + writer.WriteLine(title + " "); + writer.WriteLine(new String('-', 50) + " "); + } + writer.WriteLine(page.ContentInnerText); + writer.WriteLine("\r\n"); + writer.Flush(); + } + + protected override void EndCreateFile(StreamWriter writer) + { + //Nothing to do + } + } +} diff --git a/NoteWidgetAddIn/Export/OneNoteHostedExportor.cs b/NoteWidgetAddIn/Export/OneNoteHostedExportor.cs new file mode 100644 index 0000000..a6c3250 --- /dev/null +++ b/NoteWidgetAddIn/Export/OneNoteHostedExportor.cs @@ -0,0 +1,30 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Office.Interop.OneNote; + +namespace NoteWidgetAddIn.Export +{ + internal class OneNoteHostedExporter : AbstractExportor + { + public OneNoteHostedExporter(ExportFormat fileFormat) : base(fileFormat) + { + } + + public override void ExportNodeToSingleFile(string nodeID, string filePath) + { + ExceptionAssertion.ThrowArgumentNullExceptionIfNull(nodeID, nameof(nodeID)); + CreatePageFile(nodeID, filePath); + } + + protected override void CreatePageFile(string nodeID, string file) + { + NoteApp.Publish(nodeID, (PublishFormat)FileFormat, file); + } + } +} diff --git a/NoteWidgetAddIn/Markdown/Extension/ColorSchemeExtension.cs b/NoteWidgetAddIn/Markdown/Extension/ColorSchemeExtension.cs new file mode 100644 index 0000000..f609b56 --- /dev/null +++ b/NoteWidgetAddIn/Markdown/Extension/ColorSchemeExtension.cs @@ -0,0 +1,59 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NoteWidgetAddIn.Markdown.Extension +{ + internal class ColorSchemeExtension : ITemplateExtension + { + internal class ColorSchemeRender : ITemplateRender + { + public ColorScheme ColorScheme { get; set; } + public TemplateResourceType ResourceType { get; set; } + public void Render(HtmlTemplate template) + { + string githubCssFileName; + string schemeStyleVar; + if (ColorScheme == ColorScheme.Light) + { + githubCssFileName = "github-markdown-light.css"; + schemeStyleVar = "body{--color-previewwindow-default: #ffffff;}.notewidget-footer{--color-fg-default:#24292f;--color-canvas-default:#ffffff}"; + } + else if (ColorScheme == ColorScheme.Dark) + { + githubCssFileName = "github-markdown-dark.css"; + schemeStyleVar = "body{--color-previewwindow-default: #202020;}.notewidget-footer{--color-fg-default:#c9d1d9;--color-canvas-default:#202020;}::-webkit-scrollbar { width: 10px; height: 10px;}::-webkit-scrollbar-button { background-color: #666; }::-webkit-scrollbar-track { background-color: #202020;}::-webkit-scrollbar-track-piece { background-color: #000;}::-webkit-scrollbar-thumb { height: 50px; background-color: #666; border-radius: 3px;}::-webkit-scrollbar-corner { background-color: #202020;}::-webkit-resizer { background-color: #666;}"; + } + else //Use System Settings + { + githubCssFileName = "github-markdown.min.css"; + schemeStyleVar = "@media (prefers-color-scheme: dark) {body{--color-previewwindow-default: #202020;}.notewidget-footer{--color-fg-default:#c9d1d9;--color-canvas-default:#0d1117;}::-webkit-scrollbar { width: 10px; height: 10px;}::-webkit-scrollbar-button { background-color: #666; }::-webkit-scrollbar-track { background-color: #202020;}::-webkit-scrollbar-track-piece { background-color: #000;}::-webkit-scrollbar-thumb { height: 50px; background-color: #666; border-radius: 3px;}::-webkit-scrollbar-corner { background-color: #202020;}::-webkit-resizer { background-color: #666;}}@media(prefers-color-scheme: light){body{--color-previewwindow-default: #ffffff;}.notewidget-footer{--color-fg-default:#24292f;--color-canvas-default:#ffffff}}"; + } + string schemeStyle = ""; + + string gitHubCssUrl; + if (ResourceType == TemplateResourceType.Local) + { + gitHubCssUrl = $"http://notewidget-vitual-host/resources/css/{githubCssFileName}"; + } + else + { + gitHubCssUrl = $"https://cdn.jsdelivr.net/npm/github-markdown-css/{githubCssFileName}"; + } + template.Stylesheets.Add($""); + template.Stylesheets.Add(schemeStyle); + } + } + public void Setup(HtmlTemplateBuilder builder, TemplateResourceType resourceType) + { + var scheme = Enum.TryParse(Properties.Settings.Default.Markdown_ColorScheme ?? String.Empty, out var result) ? result : ColorScheme.System; + var render = new ColorSchemeRender { ColorScheme = scheme, ResourceType = resourceType }; + builder.Renders.Add(render); + } + } +} diff --git a/NoteWidgetAddIn/Markdown/Extension/DiagramExtension.cs b/NoteWidgetAddIn/Markdown/Extension/DiagramExtension.cs new file mode 100644 index 0000000..48ac290 --- /dev/null +++ b/NoteWidgetAddIn/Markdown/Extension/DiagramExtension.cs @@ -0,0 +1,37 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NoteWidgetAddIn.Markdown.Extension +{ + internal class DiagramExtension : ITemplateExtension + { + internal class DiagramRender : ITemplateRender + { + public TemplateResourceType ResourceType { get; set; } + public void Render(HtmlTemplate template) + { + string mermaidJsUrl; + if (ResourceType == TemplateResourceType.Local) + { + mermaidJsUrl = "http://notewidget-vitual-host/resources/js/mermaid.min.js"; + } + else + { + mermaidJsUrl = "https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"; + } + template.PostScripts.Add($""); + template.PostScripts.Add(""); + } + } + public void Setup(HtmlTemplateBuilder builder, TemplateResourceType resourceType) + { + builder.Renders.Add(new DiagramRender { ResourceType = resourceType }); + } + } +} diff --git a/NoteWidgetAddIn/Markdown/Extension/HighlightExtension.cs b/NoteWidgetAddIn/Markdown/Extension/HighlightExtension.cs new file mode 100644 index 0000000..b9da744 --- /dev/null +++ b/NoteWidgetAddIn/Markdown/Extension/HighlightExtension.cs @@ -0,0 +1,49 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NoteWidgetAddIn.Markdown.Extension +{ + internal class HighlightExtension : ITemplateExtension + { + internal class HighlightTemplateRender : ITemplateRender + { + public HighlightTheme HighlightTheme { get; set; } + public TemplateResourceType ResourceType { get; set; } + public void Render(HtmlTemplate template) + { + string highlightCssFileName; + if (HighlightTheme == HighlightTheme.Default) + { + highlightCssFileName = "prism.css"; + } + else + { + highlightCssFileName = $"prism-{HighlightTheme.ToString().ToLower()}.min.css"; + } + if (ResourceType == TemplateResourceType.Local) + { + template.Stylesheets.Add($""); + template.PostScripts.Add(""); + } + else + { + template.Stylesheets.Add($""); + template.PostScripts.Add(""); + template.PostScripts.Add(""); + } + } + } + public void Setup(HtmlTemplateBuilder builder, TemplateResourceType resourceType) + { + var theme = Enum.TryParse(Properties.Settings.Default.Markdown_HighlightTheme ?? String.Empty, out var result) ? result : HighlightTheme.Default; + var render = new HighlightTemplateRender { HighlightTheme = theme, ResourceType = resourceType }; + builder.Renders.Add(render); + } + } +} diff --git a/NoteWidgetAddIn/Markdown/HtmlTemplate.cs b/NoteWidgetAddIn/Markdown/HtmlTemplate.cs new file mode 100644 index 0000000..8dee759 --- /dev/null +++ b/NoteWidgetAddIn/Markdown/HtmlTemplate.cs @@ -0,0 +1,88 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Web; +using Markdig; + +namespace NoteWidgetAddIn.Markdown +{ + public class HtmlTemplate + { + static HtmlTemplate() + { + BuildDefaultTemplates(); + } + #region consts + private const string HTML_HEAD = @" + + + + + {{HeadContent}} + {{Title}} + + +
"; + private const string HTML_FOOT = @" +
+
+

{{footer}}

+
+ {{FootContent}} + + +"; + #endregion + public static HtmlTemplate LocalResourceTemplate { get; private set; } + public static HtmlTemplate OnlineResourceTemplate { get; private set; } + public static void BuildDefaultTemplates() + { + var templateBuilder = HtmlTemplateBuilder.CreateDefaultHtmlTemplateBuilder(TemplateResourceType.Local); + LocalResourceTemplate = templateBuilder.Build(); + templateBuilder = HtmlTemplateBuilder.CreateDefaultHtmlTemplateBuilder(TemplateResourceType.Online); + OnlineResourceTemplate = templateBuilder.Build(); + } + + public IList Stylesheets { get; } + public IList Scripts { get; } + public IList PostScripts { get; } + public HtmlTemplate() + { + Stylesheets = new List(); + Scripts = new List(); + PostScripts = new List(); + } + public string ToHead(string title) + { + StringBuilder stringBuilder = new StringBuilder(); + foreach(var style in Stylesheets) + { + stringBuilder.AppendLine($"\t\t{style}"); + } + + foreach(var script in Scripts) + { + stringBuilder.AppendLine($"\t\t{script}"); + } + + return HTML_HEAD.Replace("{{HeadContent}}", stringBuilder.ToString()).Replace("{{Title}}", HttpUtility.HtmlDecode(title ?? string.Empty)); + } + public string ToFoot(string footer = null) + { + StringBuilder stringBuilder = new StringBuilder(); + foreach (var script in PostScripts) + { + stringBuilder.AppendLine($"\t\t{script}"); + } + return HTML_FOOT.Replace("{{footer}}", footer ?? string.Empty).Replace("{{FootContent}}", stringBuilder.ToString()); + } + + public string ToHtml(string title, string htmlBodyContent, string footer = null) + { + return ToHead(title) + htmlBodyContent + ToFoot(footer); + } + } +} diff --git a/NoteWidgetAddIn/Markdown/HtmlTemplateBuilder.cs b/NoteWidgetAddIn/Markdown/HtmlTemplateBuilder.cs new file mode 100644 index 0000000..2f0c520 --- /dev/null +++ b/NoteWidgetAddIn/Markdown/HtmlTemplateBuilder.cs @@ -0,0 +1,68 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NoteWidgetAddIn.Markdown.Extension; + +namespace NoteWidgetAddIn.Markdown +{ + public class HtmlTemplateBuilder + { + private HtmlTemplateBuilder(TemplateResourceType resourceType) + { + _extensions = new List(); + Renders = new List(); + ResourceType = resourceType; + } + public TemplateResourceType ResourceType { get; } + private List _extensions; + public IEnumerable Extensions + { + get + { + return _extensions; + } + } + public HtmlTemplateBuilder AddExtensionIfNotExists() where T: ITemplateExtension, new() + { + if (!Contains()) + { + _extensions.Add(new T()); + } + return this; + } + + public bool Contains() + { + return _extensions.Any(e => e is T); + } + + public static HtmlTemplateBuilder CreateDefaultHtmlTemplateBuilder(TemplateResourceType resourceType) + { + return new HtmlTemplateBuilder(resourceType) + .AddExtensionIfNotExists() + .AddExtensionIfNotExists() + .AddExtensionIfNotExists(); + } + + public List Renders { get; } + + public HtmlTemplate Build() + { + foreach(var extension in Extensions) + { + extension.Setup(this, ResourceType); + } + var template = new HtmlTemplate(); + foreach(var render in Renders) + { + render.Render(template); + } + return template; + } + } +} diff --git a/NoteWidgetAddIn/Markdown/ITemplateExtension.cs b/NoteWidgetAddIn/Markdown/ITemplateExtension.cs new file mode 100644 index 0000000..61f78c4 --- /dev/null +++ b/NoteWidgetAddIn/Markdown/ITemplateExtension.cs @@ -0,0 +1,48 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NoteWidgetAddIn.Markdown +{ + public enum TemplateResourceType + { + Local, + Online + } + public enum ColorScheme + { + /// + /// Follow system theme. Default theme. + /// + [Description("Use system setting")] + System = 0, + [Description("Light")] + Light = 1, + [Description("Dark")] + Dark = 2 + } + /// + /// Source code hight theme + /// + public enum HighlightTheme + { + Default, + Coy, + Dark, + Funky, + Okaidia, + Solarizedlight, + Tomorrow, + Twilight + } + public interface ITemplateExtension + { + void Setup(HtmlTemplateBuilder builder, TemplateResourceType resourceType); + } +} diff --git a/NoteWidgetAddIn/Markdown/ITemplateRender.cs b/NoteWidgetAddIn/Markdown/ITemplateRender.cs new file mode 100644 index 0000000..d8c95d3 --- /dev/null +++ b/NoteWidgetAddIn/Markdown/ITemplateRender.cs @@ -0,0 +1,16 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NoteWidgetAddIn.Markdown +{ + public interface ITemplateRender + { + void Render(HtmlTemplate template); + } +} diff --git a/NoteWidgetAddIn/Model/NodeType.cs b/NoteWidgetAddIn/Model/NodeType.cs new file mode 100644 index 0000000..71eaca4 --- /dev/null +++ b/NoteWidgetAddIn/Model/NodeType.cs @@ -0,0 +1,19 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NoteWidgetAddIn.Model +{ + public enum NodeType + { + Notebook, + SectionGroup, + Section, + Page + } +} diff --git a/NoteWidgetAddIn/Model/NoteNode.cs b/NoteWidgetAddIn/Model/NoteNode.cs new file mode 100644 index 0000000..cf032ba --- /dev/null +++ b/NoteWidgetAddIn/Model/NoteNode.cs @@ -0,0 +1,180 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace NoteWidgetAddIn.Model +{ + public class NoteNode + { + public NoteNode(NoteNode parent, NodeType nodeType) + { + Parent = parent; + NodeType = nodeType; + + Children = new List(); + } + + public NoteNode Parent { get; private set; } + public NodeType NodeType { get; private set; } + public bool Colored + { + get + { + bool result = false; + switch (NodeType) + { + case NodeType.Notebook: + case NodeType.Section: + result = true; + break; + } + + return result; + } + } + + public string ID { get; set; } + public string Name { get; set; } + public string Nickname { get; set; } + public string CreatedTime { get; set; } + public string LastModifiedTime { get; set; } + public bool IsCurrentlyViewed { get; set; } + public string Color { get; set; } + public string Path { get; set; } + public int PageLevel { get; set; } + + public ICollection Children { get; protected set; } + + /// + /// + /// + /// + /// + public static ICollection HierarchicalNodesFrom(string xmlContent) + { + ExceptionAssertion.ThrowArgumentNullExceptionIfNull(xmlContent, nameof(xmlContent)); + XDocument xdoc = XDocument.Parse(xmlContent); + ICollection result = new List(); + + if (xdoc != null) + { + var localName = xdoc.Root.Name.LocalName == "Notebooks" ? "Notebook" : xdoc.Root.Name.LocalName; + var nodeType = (NodeType)Enum.Parse(typeof(NodeType), localName); + var ns = xdoc.Root.Name.Namespace; + foreach (var xe in xdoc.Descendants(ns + nodeType.ToString())) + { + var node = CreateNoteNode(nodeType, null, xe); + result.Add(node); + + if (nodeType != NodeType.Page) + { + LoadChildren(node, xdoc); + } + } + } + + return result; + } + private static void LoadChildren(NoteNode parent, XDocument xdoc) + { + var desendants = xdoc.Descendants() + .Where(e => e.Parent?.Attribute("ID")?.Value == parent.ID + && !(e.Attribute("isRecycleBin")?.Value == "true" || e.Attribute("isInRecycleBin")?.Value == "true")); + foreach (var xe in desendants) + { + var nodeType = (NodeType)Enum.Parse(typeof(NodeType), xe.Name.LocalName); + + var node = CreateNoteNode(nodeType, parent, xe); + if (node.NodeType != NodeType.Page) + { + parent.Children.Add(node); + LoadChildren(node, xdoc); + } + else + { + if (node.PageLevel == 1) + { + parent.Children.Add(node); + } + else + { + NoteNode parentPage = parent.Children.LastOrDefault(); + NoteNode last = parentPage; + while (true) + { + if (node.PageLevel - parentPage.PageLevel == 1 || last == null) + { + parentPage.Children.Add(node); + break; + } + else if (last.Children.Count == 0) + { + last.Children.Add(node); + break; + } + + if (parentPage.ID != last.ID) + { + parentPage = last; + } + + last = parentPage.Children.LastOrDefault(); + } + } + } + } + } + private static NoteNode CreateNoteNode(NodeType nodeType, NoteNode parent, XElement xelement) + { + var node = new NoteNode(parent, nodeType); + node.ID = xelement.Attribute("ID")?.Value; + node.Name = xelement.Attribute("name")?.Value; + node.LastModifiedTime = xelement.Attribute("lastModifiedTime")?.Value; + node.IsCurrentlyViewed = xelement.Attribute("isCurrentlyViewed")?.Value == "true"; + + if (nodeType == NodeType.Notebook) + { + node.Color = xelement.Attribute("color")?.Value; + node.Path = xelement.Attribute("path")?.Value; + node.Nickname = xelement.Attribute("nickname")?.Value; + } + else if (nodeType == NodeType.SectionGroup) + { + node.Path = xelement.Attribute("path")?.Value; + } + else if (nodeType == NodeType.Section) + { + node.Color = xelement.Attribute("color")?.Value; + node.Path = xelement.Attribute("path")?.Value; + } + else if (nodeType == NodeType.Page) + { + node.CreatedTime = xelement.Attribute("dateTime")?.Value; + node.PageLevel = int.Parse(xelement.Attribute("pageLevel")?.Value ?? "1"); + } + + return node; + } + + #region EmptySequence + private static IEnumerable s_emptySequence; + public static IEnumerable EmptySequence + { + get + { + if (s_emptySequence == null) + { + s_emptySequence = new NoteNode[0]; + } + return s_emptySequence; + } + } + #endregion + } +} diff --git a/NoteWidgetAddIn/Model/NotePage.cs b/NoteWidgetAddIn/Model/NotePage.cs new file mode 100644 index 0000000..f8be5cf --- /dev/null +++ b/NoteWidgetAddIn/Model/NotePage.cs @@ -0,0 +1,238 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Xml.Linq; + +namespace NoteWidgetAddIn.Model +{ + public class NotePage + { + #region Element class + public class NoteTextRange + { + public NoteTextRange(XElement xe) + { + ExceptionAssertion.ThrowArgumentNullExceptionIfNull(xe, nameof(xe)); + if (xe.Name.LocalName != "T") + { + throw new InvalidCastException($"Invalid element: {xe.Name}. "); + } + Root = xe; + } + public XElement Root { get; } + /// + /// Raw value of element. + /// May contains formated styles. E.g.function to create embedded image string as base64]]> + /// + public string Value + { + get + { + return Root.Value; + } + } + /// + /// Inner Text of TextRange () element. + /// Formated styles is removed. + /// + public string InnerText + { + get + { + var htmlContent = Root.Value; + if (string.IsNullOrEmpty(htmlContent)) + { + return htmlContent; + } + var htmlDoc = new HtmlAgilityPack.HtmlDocument(); + htmlDoc.LoadHtml(htmlContent); + return HttpUtility.HtmlDecode(htmlDoc.DocumentNode.InnerText); + } + } + } + public class NoteImage + { + public NoteImage(XElement xe) + { + ExceptionAssertion.ThrowArgumentNullExceptionIfNull(xe, nameof(xe)); + if (xe.Name.LocalName != "Image") + { + throw new InvalidCastException($"Invalid element: {xe.Name}. "); + } + Root = xe; + } + public XElement Root { get; } + /// + /// Image format. Png, Jpg etc. + /// + public string Format + { + get + { + return Root.Attribute("format")?.Value; + } + } + public Size Size + { + get + { + var e = Root.Element(Root.Name.Namespace + "Size"); + if (e != null) + { + return new Size(int.Parse(e.Attribute("width")?.Value ?? "0"), int.Parse(e.Attribute("height")?.Value ?? "0")); + } + return new Size(0, 0); + } + } + public string Data + { + get + { + return Root.Element(Root.Name.Namespace + "Data")?.Value?.Replace("\r", "").Replace("\n", ""); + } + } + public string ToBase64Image() + { + return $"data:image/{Format};base64,{Data}"; + } + public void Save(string imageFilePath) + { + System.IO.File.WriteAllBytes(imageFilePath, Convert.FromBase64String(Data)); + } + } + #endregion + + public const string MarkdownFlag = "IsMarkdownPage"; + public NotePage(XElement xelement) + { + ExceptionAssertion.ThrowArgumentNullExceptionIfNull(xelement, nameof(xelement)); + if (xelement.Name.LocalName != "Page") + { + throw new InvalidOperationException($"Invalid argument: {xelement.Name}"); + } + Root = xelement; + PageID = Root.Attribute("ID").Value; + Namespace = Root.Name.Namespace; + } + public string PageID { get;} + public XElement Root { get;} + /// + /// Root Namespace + /// + public XNamespace Namespace { get; } + public NoteTextRange Title + { + get + { + var oe = Root.Descendants(Namespace + "Title").FirstOrDefault()?.Descendants(Namespace + "OE").FirstOrDefault(); + XElement tr = new XElement(Namespace + "T", new XCData(oe?.Value)); + return new NoteTextRange(tr); + } + set + { + var toe = Root.Descendants(Namespace + "Title").FirstOrDefault().Descendants(Namespace + "OE").FirstOrDefault(); + toe?.ReplaceNodes(new XElement(Namespace + "T", new XCData(value.Value))); + } + } + /// + /// + /// + public string ContentInnerText + { + get + { + StringBuilder contentBuilder = new StringBuilder(); + AppendElementsInnerText(contentBuilder, Root); + return contentBuilder.ToString().TrimEnd('\r', '\n'); + } + } + private void AppendElementsInnerText(StringBuilder appender, XElement container) + { + foreach(var item in container.Elements()) + { + if (item.Name.LocalName == "Outline") + { + foreach (var oe in item.Elements(Namespace + "OEChildren").Elements(Namespace + "OE")) + { + AppendElementsInnerText(appender, oe); + } + } + else if (item.Name.LocalName == "Image") + { + var ni = new NoteImage(item); + //TODO: Large image (more than 2MB) should be saved to file, not embedded in html content. + appender.AppendLine($"![]({ni.ToBase64Image()})"); + } + else if (item.Name.LocalName == "T") + { + var tr = new NoteTextRange(item); + appender.AppendLine(tr.InnerText); + } + else if (item.Name.LocalName == "Table" && item.Attribute("hasHeaderRow")?.Value == "false") + { + foreach(var oe in item.Descendants(Namespace + "OE")) + { + AppendElementsInnerText(appender, oe); + } + } + else if (item.Name.LocalName == "OEChildren") + { + foreach (var oe in item.Elements(Namespace + "OE")) + { + if (oe.Elements(Namespace + "T").Count() > 0) + { + var tr = new NoteTextRange(new XElement(Namespace + "T", new XCData(oe.Value))); + appender.AppendLine(tr.InnerText); + } + else + { + AppendElementsInnerText(appender, oe); + } + } + } + + } + } + public void AddCustomTagToTitle(string tagName, string symbol) + { + var index = 10000.ToString(); + Root.AddFirst( + new XElement(Namespace + "TagDef", + new XAttribute("index", index), + new XAttribute("type", "0"), + new XAttribute("symbol", symbol), + new XAttribute("name", tagName) + )); + var tag = new XElement(Namespace + "Tag", + new XAttribute("index", index), + new XAttribute("completed", "true"), + new XAttribute("disabled", "false") + ); + Root.Element(Namespace + "Title").Element(Namespace + "OE").AddFirst(tag); + } + public void AddCustomMeta(string name, string value) + { + if (!Root.Elements(Namespace + "Meta").Any(e => e.Attribute("name")?.Value == MarkdownFlag)) + { + Root.AddFirst(new XElement(Namespace + "Meta", + new XAttribute("name", name), + new XAttribute("content", value))); + } + } + public void SetMarkdownFlag() + { + AddCustomMeta(MarkdownFlag, "true"); + } + public override string ToString() + { + return $"NotePage PageID:{PageID}"; + } + } +} diff --git a/NoteWidgetAddIn/Model/NotePageInfo.cs b/NoteWidgetAddIn/Model/NotePageInfo.cs new file mode 100644 index 0000000..981f52e --- /dev/null +++ b/NoteWidgetAddIn/Model/NotePageInfo.cs @@ -0,0 +1,57 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using Microsoft.Office.Interop.OneNote; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NoteWidgetAddIn.Model +{ + public enum NotePageInfo + { + /// + /// Returns only basic page content, without selection markup, file types for binary data objects and binary data objects. + /// This is the standard value to pass. + /// Value = 0 + /// + Basic = PageInfo.piBasic, + /// + /// Returns page content with no selection markup, but with all binary data. + /// Value = 1 + /// + BinaryData = PageInfo.piBinaryData, + /// + /// Returns page content with selection markup, but no binary data. + /// Value = 2 + /// + Selection = PageInfo.piSelection, + /// + /// Returns page content with selection markup and all binary data. + /// Value = 3 + /// + BinaryDataSelection = PageInfo.piBinaryDataSelection, + /// + /// Returns page content with file type info for binary data objects. + /// Value = 4 + /// + FileType = PageInfo.piFileType, + /// + /// Returns page content with file type info for binary data objects and binary data objects + /// Value = 5 + /// + BinaryDataFileType = PageInfo.piBinaryDataFileType, + /// + /// Returns page content with selection markup and file type info for binary data. + /// Value = 6 + /// + SelectionFileType = PageInfo.piSelectionFileType, + /// + /// Returns all page content. + /// Value = 7 + /// + All = PageInfo.piAll, + } +} diff --git a/NoteWidgetAddIn/NLog.config b/NoteWidgetAddIn/NLog.config new file mode 100644 index 0000000..59b5838 --- /dev/null +++ b/NoteWidgetAddIn/NLog.config @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/NoteWidgetAddIn/NoteApplication.cs b/NoteWidgetAddIn/NoteApplication.cs new file mode 100644 index 0000000..5b7c915 --- /dev/null +++ b/NoteWidgetAddIn/NoteApplication.cs @@ -0,0 +1,144 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using Microsoft.Office.Interop.OneNote; +using NLog; +using NoteWidgetAddIn.Model; + +#pragma warning disable CS3001 // Type is not CLS-compliant +namespace NoteWidgetAddIn +{ + public sealed class NoteApplication : IDisposable + { + #region Helpers + private class SimpleWin32Window : System.Windows.Forms.IWin32Window + { + public SimpleWin32Window(long windowHandle) + { + Handle = new IntPtr(windowHandle); + } + public IntPtr Handle { get; } + } + + public static System.Windows.Forms.IWin32Window CreateWin32Window(long handle) + { + return new SimpleWin32Window(handle); + } + #endregion + + private readonly NoteApplicationContext _context; + private IApplication _application; + internal NoteApplication(NoteApplicationContext context) + { + _context = context; + _application = context.ResisteredApplicationType == null? new Application() : + (IApplication)Activator.CreateInstance(_context.ResisteredApplicationType); + } + + public string CurrentNotebookID => _application?.Windows.CurrentWindow?.CurrentNotebookId; + public string CurrentSectionGroupID => _application?.Windows.CurrentWindow?.CurrentSectionGroupId; + public string CurrentSectionID => _application?.Windows.CurrentWindow?.CurrentSectionId; + public string CurrentPageID => _application?.Windows.CurrentWindow?.CurrentPageId; + public System.Windows.Forms.IWin32Window CreateCurrentWin32Window() => CreateWin32Window((long)(_application?.Windows.CurrentWindow?.WindowHandle ?? 0)); + + #region NoteNode + public ICollection GetAllNotebookHierarchy() + { + var xmlOut = GetHierarchy(null, HierarchyScope.hsPages); + + if (!string.IsNullOrEmpty(xmlOut)) + { + return NoteNode.HierarchicalNodesFrom(xmlOut); + } + + return new List(); + } + public NoteNode GetNoteNodeHierarchy(string startNodeId) + { + if (string.IsNullOrEmpty(startNodeId)) + throw new ArgumentNullException("startNodeId"); + + _application.GetHierarchy(startNodeId, HierarchyScope.hsPages, out var xmlOut); + + if (!string.IsNullOrEmpty(xmlOut)) + { + return NoteNode.HierarchicalNodesFrom(xmlOut).FirstOrDefault(); + } + return null; + } + #endregion + + #region Hierarchy + /// + /// Returns xml hierarchy for specified startNodeID. Returns all notebooks hierarchy if startNodeID is null. + /// + /// An ID of a Notebook/Section Group/Section/Page. + /// + /// + public string GetHierarchy(string startNodeID, HierarchyScope scope) + { + _application.GetHierarchy(startNodeID, scope, out var xmlOut); + return xmlOut; + } + #endregion + + #region Page Content + public void NewMarkdownPage() + { + var sectionID = CurrentSectionID; + if (sectionID == null) + { + throw new InvalidOperationException("No Section is currently viewed."); + } + _application.CreateNewPage(sectionID, out var newPageID); + var page = GetNotePage(newPageID); + page.SetMarkdownFlag(); + UpdatePage(page); + } + public NotePage GetCurrentNotePage(NotePageInfo pageInfo = NotePageInfo.All) + { + return GetNotePage(CurrentPageID, pageInfo); + } + public NotePage GetNotePage(string pageID, NotePageInfo pageInfo = NotePageInfo.All) + { + ExceptionAssertion.ThrowArgumentNullExceptionIfNull(pageID, nameof(pageID)); + _application.GetPageContent(pageID, out var xmlOut, (PageInfo)pageInfo, XMLSchema.xs2013); + if (!string.IsNullOrEmpty(xmlOut)) + { + return new NotePage(XElement.Parse(xmlOut)); + } + return null; + } + + public void DeletePageContent(string pageID, string objectID) + { + _application.DeletePageContent(pageID, objectID); + } + + public void UpdatePage(NotePage page) + { + _application.UpdatePageContent(page.Root.ToString(SaveOptions.DisableFormatting), DateTime.MinValue, XMLSchema.xs2013, true); + } + #endregion + + #region Export + public void Publish(string nodeID, PublishFormat format, string filePath) + { + ExceptionAssertion.ThrowArgumentNullExceptionIfNull(nodeID, nameof(nodeID)); + ExceptionAssertion.ThrowArgumentNullExceptionIfNull(filePath, nameof(filePath)); + _application.Publish(nodeID, filePath, format); + } + #endregion + + #region IDisposable + public void Dispose() + { + _application = null; + } + #endregion + } +} diff --git a/NoteWidgetAddIn/NoteApplicationContext.cs b/NoteWidgetAddIn/NoteApplicationContext.cs new file mode 100644 index 0000000..1ce96e0 --- /dev/null +++ b/NoteWidgetAddIn/NoteApplicationContext.cs @@ -0,0 +1,39 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using Microsoft.Office.Interop.OneNote; + +namespace NoteWidgetAddIn +{ + public class NoteApplicationContext + { + public NoteApplicationContext() + { + ResisteredApplicationType = null; + } + /// + /// Construct context with specified type. Usually for testing purpose + /// + /// A type inherit from IApplication + /// + public NoteApplicationContext(Type type) + { + ExceptionAssertion.ThrowArgumentNullExceptionIfNull(type, nameof(type)); + if (!typeof(IApplication).IsAssignableFrom(type)) + { + throw new InvalidOperationException($"{nameof(type)} '{type.FullName}' must be derived from Microsoft.Office.Interop.OneNote.IApplication"); + } + if (type.IsInterface || type.IsAbstract) + { + throw new InvalidOperationException($"{nameof(type)} cannot be interface or abstract."); + } + ResisteredApplicationType = type; + } + public Type ResisteredApplicationType { get;} + public NoteApplication CreateApplication() + { + return new NoteApplication(this); + } + } +} diff --git a/NoteWidgetAddIn/NoteWidgetAddIn.csproj b/NoteWidgetAddIn/NoteWidgetAddIn.csproj new file mode 100644 index 0000000..b47c43e --- /dev/null +++ b/NoteWidgetAddIn/NoteWidgetAddIn.csproj @@ -0,0 +1,280 @@ + + + + + Debug + AnyCPU + {280104F5-13BA-4193-BFF5-5A5C48261640} + Library + Properties + NoteWidgetAddIn + NoteWidgetAddIn + v4.7.2 + 512 + true + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\Publish\ + DEBUG;TRACE + full + AnyCPU + 7.3 + prompt + + + true + bin\Win32\Publish\ + AnyCPU + 7.3 + + + + True + + + ..\packages\HtmlAgilityPack.1.11.40\lib\Net45\HtmlAgilityPack.dll + + + ..\packages\Markdig.0.26.0\lib\net452\Markdig.dll + + + ..\packages\Microsoft.Web.WebView2.1.0.1054.31\lib\net45\Microsoft.Web.WebView2.Core.dll + + + ..\packages\Microsoft.Web.WebView2.1.0.1054.31\lib\net45\Microsoft.Web.WebView2.WinForms.dll + + + ..\packages\Microsoft.Web.WebView2.1.0.1054.31\lib\net45\Microsoft.Web.WebView2.Wpf.dll + + + ..\packages\NLog.4.7.13\lib\net45\NLog.dll + + + + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + + + + + ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + AdvancedSettingsDialog.cs + + + + Form + + + ExportToPathDialog.cs + + + + + + + + + + + True + True + Resources.resx + + + True + True + Settings.settings + + + + + + + + + WebBrowserWindow.xaml + + + + + + ResXFileCodeGenerator + Designer + Resources.Designer.cs + + + AdvancedSettingsDialog.cs + + + ExportToPathDialog.cs + + + + + + + + + {2DF8D04C-5BFA-101B-BDE5-00AA0044DE52} + 2 + 8 + 0 + primary + False + True + + + {0EA692EE-BB50-4E3C-AEF0-356D91732725} + 1 + 1 + 0 + tlbimp + False + True + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + Designer + XamlIntelliSenseFileGenerator + + + Designer + MSBuild:Compile + + + + + + + + + + + + + + + + + + if $(ConfigurationName) == Publish ( +taskkill /fi "pid gt 0" /im ONENOTE.exe +) + + + if $(ConfigurationName) == Publish ( +call C:\Users\efrey\source\Github\OneNoteWidget\powershell-copyfile-runas.bat "$(TargetPath)" "C:\Program Files (x86)\EKStudio\NoteWidget\$(TargetFileName)" +) + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/NoteWidgetAddIn/Properties/AssemblyInfo.cs b/NoteWidgetAddIn/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0faeb06 --- /dev/null +++ b/NoteWidgetAddIn/Properties/AssemblyInfo.cs @@ -0,0 +1,42 @@ +// Copyright (c) Efrey Kong. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NoteWidgetAddIn")] +[assembly: AssemblyDescription("OneNote Widget AddIn")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("EKStudio")] +[assembly: AssemblyProduct("NoteWidgetAddIn")] +[assembly: AssemblyCopyright("Copyright \u00a9 EKStudio. 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(true)] +[assembly: CLSCompliant(true)] +[assembly: InternalsVisibleTo("NoteWidgetTests")] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("01307420-95EF-4ACA-A55A-A49BFACD2EEE")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/NoteWidgetAddIn/Properties/Resources.Designer.cs b/NoteWidgetAddIn/Properties/Resources.Designer.cs new file mode 100644 index 0000000..d424a78 --- /dev/null +++ b/NoteWidgetAddIn/Properties/Resources.Designer.cs @@ -0,0 +1,154 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace NoteWidgetAddIn.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NoteWidgetAddIn.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon documents { + get { + object obj = ResourceManager.GetObject("documents", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap markdown { + get { + object obj = ResourceManager.GetObject("markdown", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon markdown_icon { + get { + object obj = ResourceManager.GetObject("markdown_icon", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap markdownflag { + get { + object obj = ResourceManager.GetObject("markdownflag", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap openfolder { + get { + object obj = ResourceManager.GetObject("openfolder", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> + ///<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" loadImage="GetImage"> + /// <ribbon> + /// <tabs> + /// <tab idMso="TabHome"> + /// <group id="groupNoteWidgetMarkdown" label="Markdown"> + /// <button id="viewMarkdownAsHtmlButton" size="large" + /// label="Preview" + /// screentip="Preview markdown content as Html document" + /// onAction="PreviewMarkdownCmd" + /// image="markdown.png" + /// /> + /// <butto [rest of string was truncated]";. + /// + internal static string ribbon { + get { + return ResourceManager.GetString("ribbon", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon settingicon { + get { + object obj = ResourceManager.GetObject("settingicon", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap settings { + get { + object obj = ResourceManager.GetObject("settings", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/NoteWidgetAddIn/Properties/Resources.resx b/NoteWidgetAddIn/Properties/Resources.resx new file mode 100644 index 0000000..02d2008 --- /dev/null +++ b/NoteWidgetAddIn/Properties/Resources.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + documents.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + markdown.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + markdownflag.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + markdown_icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + openfolder.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ribbon.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + setting.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + settings.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/NoteWidgetAddIn/Properties/Settings.Designer.cs b/NoteWidgetAddIn/Properties/Settings.Designer.cs new file mode 100644 index 0000000..cd9a9a5 --- /dev/null +++ b/NoteWidgetAddIn/Properties/Settings.Designer.cs @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace NoteWidgetAddIn.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.0.3.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("System")] + public string Markdown_ColorScheme { + get { + return ((string)(this["Markdown_ColorScheme"])); + } + set { + this["Markdown_ColorScheme"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("Default")] + public string Markdown_HighlightTheme { + get { + return ((string)(this["Markdown_HighlightTheme"])); + } + set { + this["Markdown_HighlightTheme"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("1200")] + public double Markdown_Preview_Width { + get { + return ((double)(this["Markdown_Preview_Width"])); + } + set { + this["Markdown_Preview_Width"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("1000")] + public double Markdown_Preview_Height { + get { + return ((double)(this["Markdown_Preview_Height"])); + } + set { + this["Markdown_Preview_Height"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool Markdown_Preview_Singleton { + get { + return ((bool)(this["Markdown_Preview_Singleton"])); + } + set { + this["Markdown_Preview_Singleton"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("1500")] + public double Markdown_CheatSheet_Width { + get { + return ((double)(this["Markdown_CheatSheet_Width"])); + } + set { + this["Markdown_CheatSheet_Width"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("1000")] + public double Markdown_CheatSheet_Height { + get { + return ((double)(this["Markdown_CheatSheet_Height"])); + } + set { + this["Markdown_CheatSheet_Height"] = value; + } + } + } +} diff --git a/NoteWidgetAddIn/Properties/Settings.settings b/NoteWidgetAddIn/Properties/Settings.settings new file mode 100644 index 0000000..b4984a1 --- /dev/null +++ b/NoteWidgetAddIn/Properties/Settings.settings @@ -0,0 +1,27 @@ + + + + + + System + + + Default + + + 1200 + + + 1000 + + + True + + + 1500 + + + 1000 + + + \ No newline at end of file diff --git a/NoteWidgetAddIn/Properties/documents.ico b/NoteWidgetAddIn/Properties/documents.ico new file mode 100644 index 0000000000000000000000000000000000000000..1f15c3de21600fedf571e7ff16e07721da592c6d GIT binary patch literal 1150 zcmd6ny$*sf6on7b*)X~4=yUW*9DPUJd>lyB0m4@A0S|$OQb-&OIo$M?@BXxmiy0N{Qrtxd#y+B;TJY&p> z@ngB^SN^b1#ahdcb0{Wb{3Act>z4Y})4eFV{_47(tZ}M;&Wo+8YQm29MC%vUtMQnX zPgeUEvvV~wx9TFdJ04?tA8ri)7L-b#mO!KNtZ&xwl?2prXBDB DQJ^)_ literal 0 HcmV?d00001 diff --git a/NoteWidgetAddIn/Properties/markdown.png b/NoteWidgetAddIn/Properties/markdown.png new file mode 100644 index 0000000000000000000000000000000000000000..949d973f500ecc2b987e6b89ece0bb60f1b2d3a3 GIT binary patch literal 3796 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 literal 0 HcmV?d00001 diff --git a/NoteWidgetAddIn/Properties/markdown_icon.ico b/NoteWidgetAddIn/Properties/markdown_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8fe43ea047cb066d59270ea7df4cc8689f26398c GIT binary patch literal 112117 zcmeEP2RxVG_x}*3Nz%|jgCq$_B}q$5k`$4>OGt>w3|ZMLWQ8OvSqTYA2-%w=TlVJu z@74b!2`$z4`}=;Lm&dd2bMHCleeOBup8Gt{2ZO=G%*CJu4?~49WyD});l959r(;?o zJWMM*$I1Es#|JT(<$LfjjPM*P|9~2U*{2QnsQ&+$1cRyb!o!fjExImGfWcUW<6+Er zd5$h#uzCTkdhzjNhxyP|v=X7FFRDI(Z8Gv4KYV~+v$Qo{LB*}e_2WQtf^y0d!%Z>D zLbN9zM;^6(-&|~7=5fbejhTn;-u(cj(?$G6YS()*^F6c^%Y)n0D-x~+(d5|&?sa^~ z|y9h8K?c@$p5+KA-dEITOzZhnNg8f(vRnX*9RD!H#%oriPI%JX2ggWb&SS- zOLN(74<3u?L@#+FJX-wNi+2=RPi|Ssf4=GveL0c&5p{C<<;QdxKY;CiTc`*)c@!Db*{< z)~v@IxnKN-v!;KU!|ECW`VD?0`Z})o2ey#l^Gcs57BoH>?)RA4)pFIaq1^^AaQDJ+aM9D4-aAzz{p2u>fZRs$mMYrZxU_}ne&OV zx>a;@7!0>a1SQ;RE(%??XfFAxRkT`(c*9AQ!+3O#4{Q6hy0UhWuU<_za8skTG}U(F z(G$9qfq@I~G@FB?Uy}me+E+{O-o0y1hfy8)@aU1`o>49?u2mEiAA+MR=`QF6e~2s+ z-D-ik_)OFGTKyZxVU81id_B+rcG~;BGOWPMQ4l=HcnAF{OMQ6GN+BH2>l4ha~#LWfATtB~P9_Nxy9y6AQ~> z24^WSIzlKndLiCFv9fRB)#17fcXxMbO-+~F+}y`K*5cZ{%kinGKPC(@(Ab+D+w|h> z>3ykf6>$scHUkYkwR2RSRiPxIpd#-29=%a^<-`%zh=>Tj>yBOvmg0xu@dc74CnpQi zuTW!Kmz9;}CfX@sp_%z!=~7;F+Aepdd)V)y1XS<9g-#6&A-Us150k5AQ;HIIJF^p?w~f=wN_D9B3e+G*S8f&-7M1quBp=6{Jx%Ahjvn1}bMT2^ z(=vx!5a|kW<@q>CEhGDVEjIPYh^1c$S$RUPVbM2T|sw-Na`!|HQ#_ zM4UTSK4g+Zl9S)P+mOvML=OQYbl$mZSK4;Hfs+guV|blvR~nWcA>v#*-!!?quTLsc zX#QLyLh2Q&v;y5W6@TD2#yE8Kw+53~aZx^6ba;cUAwhL-YuO@V z;%m)?+XCG-KEQ)QdT6y(AO!X$YoTEO$Vl}=OO2p*zlY_Xb-Y{yAqsS(da(2s#zCK- z?g)*&gqj*zq|hlTsf`+O>#VrCT(kZ26h3_T5Cai_S_U=RmYc>;$D{lDix^L{8M@&)M-|=3Poq{jW zA-{l>e>bGJ?w}u^cflovOP3^dbt&R1cxcHsc<`JQiA>vIpAHGnFDiQ9HPEif4!huE zH>PxHyJMU9-ag{0JK?-yfpN^WdYYF!ju39wL zl569BFpv#3kWZjF{8gPQ{fdR5@x7}VoEHY-sAdi?cSC{aTGzeJLKL# z{dTpheBWM^On{GsIC$fk zXz2Z*Rp)~oZw~b`?b>C^O(UhI#^2NycnmTQZ6Z8f(>FvNeDWNTKAB+f`A6rsZripE zvwSNC)7sklr%>hA9F^aQcIf`T`sV%cV%YSq~LAxpxTH)@Rz)bG(~S#|d8Sy$#BKNA?Ph&gmKWDR)~X>1V2oIYylyKwduOO8sf~ZQEJ0|=X08S zpl5m-7uTW5&UZaS3Q7Sw?i)95Fs`;*zV&>aS3<(Q!a|7W<)ne(&OC6J1&Uso$C{-1`DH$W3ScUO|v|=0h%bN@hq!lq@{0Bg8no< zfxt(a@uIM`fp;qtj~zO6=zvUZz=&UQ#THo%p;unxgPnQBBckkYkxa-^ZUT=G(ndi3(LVJ;6rH6+Hdtdpr zV#O%K*RO^=Pf%lC5YR%CeTa&rx*^vWcF?XqJgpz?g ztEs7Z<;pM6)pp)UAWHOng#zpsetyPgX7iyV)aco?FNkJQ3Ok>v(Y~vNQK6rEQjMkS-0>AR+>MC?2WkvW0XT zw{NI>eS(_6>sU)={2GhY7bz(O9hy2P@x6+g8=IPZ0s>6$-J=L}JFnI`|0FRbhh^2r z`r!e@-{W5mu7QDz7wl%$r#J?Z#6rl$pfiqqh8HioJ+V(a(Nrk-19F{<7AZcp z)M3s(8^E)ijOqL-Xlx;Aq0c%OI5UXQJxHW8PDtQ@nz37>MKI}%4~$gzc=k2zqTfms zDP)z`m{Q*b&D5Dd{xzZ-GUwfZUAn2c`D*ONb053Qj_HwGap4QtA$3dxpH|WHAK?N7MFReMfNg&e|FngB{+mR8~&TvtJ~l#Ii*3gIm=w z4XaylZ8)K$p=hX{jai9gxXNI+!n=-`{DM+OR=35_U=$^e_H3IU1v}+X8Rf&nn1`*; z?+h1~L;J?Kd-p5YcVJk2xim&ATl47Ac_Jbr%cCQsFG4x{^3%c4UtCu=;ay%>T^FN< zx_WM9YG`y( z3}0CZ72cJbrcs$e7DEl=ZQr8it8o=Da^n>f12%hLb?pN>#H_FKo2tdEprLD2BZYR^ zEo(VBMkcxp7DZ|X<2HwqqfNbLfd<8_cjBRa~ zattJ+nOtE^rczE0mhaQ^M%C{6qfZa?mkhX&7#9t8%Psj*pA zC~YP+b7(0~ihQNq)7I4VqE*AU;L^g?&-e}xTp?JGF*L7-p}_97OZ@%)SHXehWg8nV z-=rFq_SaiO6}ONp>IRDuapLg{1Q(9_%K4_aDhE9Eu7!Ih<9psQ6 zbQBP+IXzl?I!utBx?)>NMMc)G#DP;wC^;^w@R$s{CFZ#6*Ll$qc<~jS<<-r?+SGIP<3GRd^{lU85kWp zvd6GoGF&`TXpedm8SK>J5`p~IK!`tz{TyB$^XZ2*5_I=Z8HWU}Su_{gY6z`M)`xAL z&Nllq^BdLP78eWV9H0m)`#O zsEq?7?E~xVjB}t75Dk?R7uOf0k7~5c)QIzdeZO4kdeZ!Tewj@X%Wuu+B{(0TPIoT0 zpjZ5gzm@P}yT;a5nW}`Fn(X&Zr8QWwU_UD5CAI4e-FoJ^WXaysZi}6laLf0o^*hzr1#eQG{r`Qg z!>g}WuJ3O+^i0J4xF1y&rE$oj+Kh(Q*3>%Hnhwnc_j(0x$a)@Jiq9)~K6JsOzPZbc zKu7HaBp@FS=;j0!MV}4KH%hFhd~iwhD8sxULT1SOlbf1b zGj0y3RhHSdQp+vR6j~}()?vkW;{I-4sjW-R3-n<+%&dS_8k#$|EOY9_Q#O5$wN;~a zY;^Qs&6T36<4#+p9=bvw#!gYy-G>rVFu^xqU0G5R+vxk0pRU0Faq5Rdx30yO`>#FW z$}O8WPZACZU?SnnTaJtf<*I~JZp^E#Wb<}-=~UGX`S4pS>-w)J@VZS#hjGl5C8Vk% zj=iXKmRN5+K5rwGv=*t^;oPq6k7)J_mnn&Yqf2S@2^8yhorvWPDu71Y(B1I#hW+iA zllE+7=QVujSIm=CP~vgvh!-5MKC~+^+imW#;+c@WHklzK9>KW`-#r9Tb}W%Xo&77_ zN-qVA3qLMU(2kVrDOn&nm+HZdPIA|USq#rg9Z2x0Nch(WZR}-@V2@!N;tO7^3r`hu z)jGGT#+I8Hz3glrj@;dUfJk55&9+Kt((ZfS+1{>Fw}ZDw$Q4}j5&IlpU%*S4AFSzup8|~r8mG0 zhnsW5O00GmF7Gs;GqmbzSn;kvFQ_L_@7}3>XFzLJV)p*g)C+;l^dySzYis)zDP9Uu z<IxG}3lxG5=D#x8@Lk53?OK}i&T^>EwqyVuzUJawy{zS&Hpe`NG@ z$!Qln4%??M49`8lY~2g`yPmi=eegSPlTp}T{BBcbWzBXyAl0V(>=g_ZLk>m-LtzOg zm6si>*x}Klgm2UvQDmP)vg4yj^&3WRm_R6dfn@l|AUw+yhw7i$W zc=c%0(-rg9V@Q2@=@_3XYCbK`zrLqIyYNkC4ng$(giJ+2B2F!)^#Xz_gA!RCr`HlO z?RTMOp;H&JFe1@c^(lN_X|xvjc&5AoIk}SID#zN*wCXYzx8U6y<~(A{XWi+~MtEr*t;1zKZeAWTebR_SCq?2l ztVXl(jytU+B`|e99&oMpeu%0q%xm$Gsme3@1{XQa*zxJA6g=n0Mx7J*9x%+8o}Z zMxRlyWp(cu_grufuOV|)b5dkI%69I;%R@)*PzPVIj*E7^SyghhT2TLHFqOTr!Bv_b z#;xjvgk=ll;$81-SC_mNqONY+Fif8~YCWgC!Hfr*Xb*tQmr*~Jj61F$tQt1 z;dBZI*$K^9k~$Q8y5`e_n3^S*mhs9kHz@g4`uYdtg>~+VTyQTcxAKwp#nWEuY(zR* z`!f$-uB{2O*wq%szUJLvaMfs*ZrDPjjKcxS@yt@3hHm>;ZCH`bNG#4|$a88)lyY@E ze#9Xwr*pQ-W-KXZ>2*{+ix0YoYhNXOF1JA}i!NvD)xMol`43dq!`$Yx^hef{dNa4@OLdpXD-cu&?a$zIQKQYwCp+v*=nz_{pK4Mc$jTy0oGoLN zB72bj6hZ7h7b=SE6Q#rEOEEW}n`vF&m^RvuQ3|;G=Ei)wnn>U7lH$IjrdQ{wv1qJO zc`R9i$4F^3u&StXU^C5Ny;l7V7p=mjnAk;kTKwLJIeyg1h%-B}ijj47@razRM(EX^ zH=svKmVtvF(<8R$mY(v)Dz*es*SzQKpeI0z`vc)~8NvX^n|f+%<4zySP+F!@om4oK z!<>19yuYT5yW(zLcl_@4g(Mi$73^$6qXSICto!EOlvSk2+1KuuYCvsRe^hYoz510v z#(e1g@=cg+9>r`IyL$|^f}0l};5!?!Xvx6`Hl2}dIZg66ljbzi58cVyp+34o>Z6F1 zB;C0({OaA6Mts}n=QN<^pZ*JXd~?Z~WeQc#S@Y2D?^ zpOMQ^dfs>LlN0z=1Nc3*MB5Ut8%5~tNQzB#lU~7_f8oL2$JPP5X-As#R^a!j%R4UM zZYogL!|W7KdRt-UO`R(6bl;+cj`_R5ARADd=d`K!fi@3;O3x~luwL<195?MdF57d5 zGdq`%F4)t*E&qasgpR)z7)TToS71)5CVq2GUEI~}dPWs_-ExfUBEK_6CwvbFpL^G& zQ6sOOqw2LZbg}z~o&**r?b+$>!lp$Z<+IiE?;Q* zr2ulNpnLre6b!|#C$}%nOgWaB_UiuQ6sZf3JqvyE<9S)h*mm}a?LScm|q;`{P(zZdN`?SH5Jxx>>`<>Z{rw%w zTfNjkNl}BE!k+%P4_P>0dk;CuAku&G#-RIgBf@_u5)$8%Mmb5+-^BM{YK ziXLL|EjoD7>HaQueaDre5y26Sn+dqP(i;gjuG}RgOG?D7Cgrea@!HZ{V~VhlA*~%k z)~+HT%1q?2flSEoc4bD6uvf00rbPHBsoRY07V4KO9Vx2y4N5c2@=NZEcF&79so5vSku zOPiD=@%72CUxnFoMY~(xO1MA0**#~jX_zmQ!ouzI)>V5Acr7(%N~*JdoyZeX)yP>F zoHnnaDCVB~0{d0#WH;OuSGAW(3#r_^Z%vJWH~AusjZs|lPQ^2DpWmj`e4~mFkC{EY zjVp17$wOsZGw(eIBTkmz(7q$hdh`*&2=5I%mEy3rvhdEjX_%C~?xg5n+#Epj{BU2=wiQxgMoBzGK3(5Q3P0QTq_ukNQXpqtDqD(4oOdX9? zy3?4MAI;8#$=6?4w&_%%0QCBW`<~9`hSv9^fsDI&@{#oF$`idIgrE z!7u#tB$&5SUR|;;laKZo{n~e#iSe1`Bh(zR%QsP+vg5gblCht1{ZoP@g^*|JZjHGl zMIQ~;S0|NMr0m!{QrvP^z0ah+aZlxmgUbx_JUJL#>4&qn@9r}(ECX$MN`(s5*Lm6p zlFy3{$~8O2ygCRrIge(QU0h=vepJI_(;*3F;r8X!D_6`HNldm9JIyq3+~s&nzIw63 zjVQ+i53ZIds~h5ZoVU!bB@-xTw>OJr*%z*UUjP1@*cIxW%gF<`NSkz4I2m3Q*PYY1 zb;VYR#8VaOEIMzZUiPddkyO&WC#*d8f@t~Om>_VkWm?PqH1 zx5ey*H9gjYf~KvSjJstrgY={V~Qgr7(%L}t&BcQ z4Pk7}D&4V6tOaMF;$*yz>yFt6 zM{})JEg9X~(`rlaAK$(`f`vIf#Y%x@9_%M!oLtL{z1(ZosnwrRz zmu#w*(298vg$P${J#V@q^rqF_y2m6-mU>t)F}bdfJVGqP>Pq9rZNDIu(~rOk&x+4P zG$_T@LMkdSch`j+g*y42st)=sc~2VXjFvd!J&B@U9dFqEf^?w~x!MP!*b-_|Tb5j7 zvMscl*Z7taa1uADB&u0P-GqujIZ`Yb-dVUA@9>2fRfBZx1EYzco?+oe5~mHJUBxm= zAel^WL~c$dhM2~;XobG;MJ;VS0c%sxlQzV$b9G^o@{wllY8h(2aI(C}ZP#iRZIr7Y z$OfvK1(YjYo@rRS>FF5^fx&an=9TrgMVzLiJ=ouNvl7(rfB%lET&vpAV_sWVgu(6; zu*Uv2+qAt&?6M9K8JY%!w06q%^JBKPzuAhv*RU_AqRrVXt_|y2$-~RH# zD#Mt=2J3wjW0O-j9S95OH@FhnG1IQ{Fq*s1rQ7YNRpp^p-kpt$9;VnlkJ4AYcGJLCA!Q<*}XTN zz-U@x$~`5u)SSwi$$b`{to6Czf5?j|LiENuMg?9M78ftY`K&BAmM0Xlsa@u&vy*pyl>ZW;DK}U zpzRJvZZbjfPSrc&OYxV>9<6t!B;NO7nZ&EqRg?tR_EpM=L$YFU_SlaBa!Z#tPoP;<X^U!w z3|Up_2 zAFjKtzKS{Qd2Io~MoI@?j@6t-J&h|AMK_w>d77i;AiwTJi-<-y*K*dvYyR8qPf@QL ztvNz7C>MK;Ci8`2P2SUO3ppj#?xr-b2xzp4Z=nweidYgX(VG35OjV6zB^zbT^*Oh0 zXKj1y>9Tp>(#_?R65ieM+aK&v(_gOVw!&E|Si+HD#Rd0c%ji#T3c%0tx%?;~B=1e7 zvoK>>l6={#>t}13uNu~KNa%>W3a@;xNPXwAJk9fBV%?Xk+TVE2@mTyygf*czah-2& zs7&^op7Q7CyO(So0x@PIdc%#LCLbAh?anaWANwM<@5Q3ZN-pwMgl|<|&DqOV?0fDJ zd0M#6<-5jtA5|1Kr39Z^nZQ&YpH+;n?moPK$-D4I`LH#tqjlQRG1^LZqZ5j0F=wRYpYMTytk{MfeT2GKn7V12^6t>+4j!=qjCc#CLQDBAbu9eDBBQkglm zGi6aYuY0xN?bIX3j>T)xJ|L~tzsnZA^qMuHvE(*oA;ZHg2UIrkT#7yRGT?$SchK{a zhL_@J&ej*yJiIQcx+=_#WfhC{8ja(R%?Qk@@$LJh=ovPdE#YRoxhpeM(Oudnro+x} zseU?DY&w;k7^RfV&XUYG`T6S3mvK>S#PAT)1enI}Yi-F|d3|tBTi@xcZF1}9 zDjo1~_kM3k$A#xIzniU*z41`&hr%wRlh-8XW*eIso2vR;6^Ze58=n; z5+{lb(m+406(OQEMxNGrdNKyN5jIk*DMxZ4shO= z9eK7s=WX{bk&Wuw+PT*URVW`O_t%eDKBKIaZQRPRl!l*ePA^8@pL4ZyH*1oQ(V@8c zEvhOx(RS}^cU*k-vfGioa-IIbLDkWHw-zww487eELp(I_j$)0FZxd5)_@i4C*<7x1 z9Iu93hupy_n|3}!S6-KDMMFQ8#<}|)j$j^h+P!Kx!J1#an6c+&IKvhdbR<)`?TfDs33T0(EO|`rWV>mz_*1pXgdaH8zWX?Mp!vGQ{$dNMmN^bx?}uB7?}y0L zNrlNbYKPA`Egl?nlGAV(ct?{g!}FeOan`aWZ`zx|2>!C@Ll+Y^c%0gL^L(}1Y8s== zdvgXd@gL*uool)zO=)w;+&QvwCa3yOZgo>zp+sQTR>+j~dZ6nvz^HPX`t8*}c=?^m zcG_)RiwxNKBpllf6bS<6U5R&#!Uz_XR<0E`l)jaIoXC;o){=h%W0v&8CH-_!^6EM5PSLvev+#8yEe<&8y*J2t5wdWg}(h*-FZRD^xVCAB?rJCl*+ z38}Fd8y}}bL&KF1rgB>E6U%AXmn_`KcRgpp+l9~Nh{9Q-QXCUq>fY#`^Dd;5*VNkH zCQH57I?#+?U66BiOj>!2(HhDF!jug`s@Emz-m}-HMP!)SM=rCo)MHF}7wN{$XZR{F zmNvFVYp!nR8X7LASgkEDxLLU9U1c>^GcSK)DPn+cL$mC31j}kYo25IKwJ#HUE2+Nv zg5~{avVl$8_K3R{Uv!8aCCWWN=Z53jQ?A(uiYp(j?YVM=Q9QUPwB}|uzJe2tFM+bL z#j|xcskilac5kSO6M7lK!^}Y@*C6RYMXJbHidjyJ@sxR|oV^3@;vg|!(f!@ro)nUU z-OTX`_41_(-qBZ^WfpYi<0;)44ly!$6Zvjb^7$&?`VHlyZjx2nuvWj1;O&bKB zgRaH8Df$W_!wt;7r_R45F34NOd-kJ%#FHkQbjl9R%rwC}hh05gYV5m~(u5up0SjJU z*1xe*DOfV={{6-r=8RpYF76^e2QyWU!;I>DCaRZ_i3ui8-@MK-G}-96L%gs#*DaEk zV!6JtjML^1E-`BMag^Jy0+alnQ1NFsG+&#Y^u2f%!)%dp_zm%nb(YLD>LOb)7Z{>D zcKap{I49P89L*vRY<{+$?EFU9Gb66XyBIFAp=KwePG%dxba~w8_X>B*c_3INdYbwe zgPh<3n)I+-`e0RQ)jbQ0<_4d?Bee05_pl-rSs*=pW=UcFXc&_PeKvyM+Rt9CP4jKD2vyRiEpkCk$KZs2d9Rjli2- z*Rv&X-z|{)7`*m@U%0}V)%*?TnjhiI?65h$^xkp169?z6SyxqZvWT*+{$%`#%+jNY zJ5%~YKXzq=CS*j)JEh;^PnUmvD1(C%w7mfB#o3Bw+K3VADViBgl97K@^r@;2)hm)QHl7VnIq?>Txz~!TQ~`IcvzAQTP*1! znnfDxl%f~Z37yuU<(8B%OCR8#uba^%UA92q>m~0N3Au%LSl3kO3SN8L(LrP@+(ovx z?D|ePu@JV6xA7cHLe8DgirdCVvz!TRd_e1#x$`!?-Y@12=O7dpl3gOKj2CTcy0B4= zeQ^qTJX?16ZI|ItIPoAZOyYT=wnbocUwvJ>p59CC*mo@_w{K22zhzIn9#*~YRoyH4 z&9AQ|RI~a-^;Ik&*m>vQGJWyYl#6X0oJ!)_zt+`a>HL@XLn1h-iZOJ-q;mE>;hrT9 z=yA(dV>oH`{Sz`^|C~K$KD&jUw8Iw+FvpMZ91b}sZb%FF_0b9V_5pf5;nRYLNnU~( zTmSzA2H+N)1aK0-NdPASoCI(Zz)1i~V0dsC^fY(k*8edX^tN_=mws0!2EgHu!yjk=|GPSX z>;L~5s@Q*)VgTw#t;Qw4u6%2nUA2Yo}@c;9$cfgS1CJz7q z$g?LvgjPx?Uoh5x7y{O$f9b4D4Y*+h-6PvE{D=GqrBFeVZL zX;*KLmqFz{6&}JeQeTuqVijFMnswyZJugh6z=Xs2}n4JJ-LBf1Qot z82{LR6>vunbNdUP&6ZpQAUzaYWNaJrv;={mabxAfxRd~>${D|oo`4N8%YxUgjMwM9TmZbg?+dT=kC)5M?gpm2?u?f~xFm^a z0MJ-DUZxH1`6?vBGBUsrUXMDY3P5Y&`1MX$-2>CtW7i)n695CPZ^y5dwhjTyEv{eG z|2wfqb^lKM4e{D5()ykhTj4-ze<5z^?+LV-*PkZZ(s5?TlgE|34m8;)L|=)aQ(E5!cAxAAgFm$ z2U?3OfvraBSo{AJ{E;jo*rWhx{}cxzstaKppto4}D>+S;8^S;4IOMmr1WFfxw5(>} zCF=xiwrapJh3Gf$$JRHS_?s*g0)a==!7Bqd(DEuBcEiv8@OR^HL?{5N%yf|m$CuvT zVGv}S1uVAe0Ur)kV6w;PABVp=u@LA8yZ4!9xMw4l@J;+C;*Y&~aA+8my{ZDST91Jp zyB*NSm-%Krvw^=E(qn#YQ1mDUbe5C?Fo>d=&r3@~9|(8L0Jq3AzoKWh`u|k;*EaM5 zy&Y~}wfRr#|F;MPK*~i;0J=~Q`Lv|IXa;(#biSe++h@^MAFeK&B|(m}E9e`GKR)-h zAt?Upx9#A$XC|<}=nnLjNlaVUui$S%A^;Mkb-;(jEJ#B$B>vM_2FpirQ6KP;e*kPZ zUjs&@azGFNYyb2+@vr>Q1N3MezvBI$gg?U4ed9&Y8WW5a8)#@402X|YzM^{~{$n~Y zM*zlGBEW%G5yXhz0i6w%<8`2&!I4qW+T0C_U)2KNi~i6rh<#P(&)|P&xiF}?;|4%; z$9Q|A(Ajpj_JP`>dJyZL229uJ!?wPi&%)skF@!phsb~yF`|HQ#IRO91JuC-$MAyH< zYqAbZJT`*$1i-Oxsii+?ep?QPI$L2)!{Zoz93BN;iYdT=JpZj`K z>j20Nd<%Rf{ekHUr5~ahhySN|_#ulp=*&d1@+Ui9TGR#14w4u{xGfsjSYjq>O#mkMzeu`E%fhkHYwmXojI&`dS8R3ZQ^z^{vRQwdfU9m z=|g4hNkjlBemc$r+L=85pUVG#ul+~S$`cp(e(OTj@ph*g{}&by0?YmO<7H5PdnpfN z&X4cMY5S4!|3o=h!F*G>gA+_Qe9BvNKqK%#?>9aK z0)W1naURglY~qi4Ty|CuFyCo0PIJIcSQLo@+PN{(Mpit0V zR0j2F5Z3f*>4X?XIb;AM^3U@OKhytFUejXnMG(fS4C-KBXRrhM894Sp%OLbI-R-^b z#|SEc+hIF!Yl$S#Czw8`Jr({Pox>pBuLQX9+k+&HJD}%XKCJmO4yYZ!yYHY}E&xLq zKi?)12Ue@3!8^O#=+gL71LJ?QJs!Y}OnPiJm@hsi%gON{x&e`&m-+#CpYsM$=S)CL z>Pz&|gYml14h(TXOV=QXxt9gJPwIiU_U>S~2gSYU%BQ8GW)#?-^nmTa`8_D7neu;= zakZHz09u})oa3jZ6S`Orm1Lkd_Y>Wd%VUp?VBW`^R1CxltAj?A`)r4C*~ll_hanyx zJNm(k&_ZBCZvk`Q$Uc9L!+!>UY`fU)qn&b~>~1vZs)BuV!q^YV^lf@8@Rz?2Y#6kF z!Cc8P`D5=x+sXLDE(V4gkQJSNK{-^zBM-*vdc-0CI&(6nFFfJObooD|xqY3zV5A3D zJk2ry#o6}09SkAaPO~5l&3MrQOz6$VX!}w8kvv`tUV^niBl7=CVoC=bJAFAHf|Z}i zA|c?$q6A)O*nol3&v|5YD~itE6@COs_p^Y_SkC(E*dNt18~CGo(0ulz1p>H6fmeg=PgD9iq$$nn}yPcYvf z{FU6$`2WG)OQ5?1`KZsbMz~iOcYvh3Nx*U!idDXzBg5*?Y~qit(~RUI@IR;lvaNl< zNJI5FAIPhHZ~oV0fjNle*8nx4kCHIn^l_M20RrZ zPKz&(WA!umBRQ66>cAR5wU1~B4tx*m{2ULVGN^8B{uh-&cDUzioHJP z6>cvS0M1*LfyZtw@WC6#ViT4+*dJZ_ACBFR>M$Z#8N&w6C%Q7IjGuRg*UZ+UxnW^| z<}RFQFT-mZW7nOwYXRf2G41Dg)@Z%}aD?-^uG{~=47}fpMh(V=U;62v#ov3I3{U{2QRj3bRUudA94oaM71~g2iLH?eD@L+aB@@4(sGV{2gClzV1sN zP?^d8AKCxO^S{`-X4?M9_;03qX7k$5;%^1>s#SJ2F#d!_4=yP7@V6<1^Lw9tII8gOT z!|y-EbZB%@nEw$NF@4TG%odIREBG70`CoqqXlGQtLB^fOpzc`?sK{@aGXFnYvinv& zKZ`%A_b&NGQ2+2DME=uUT1&?;xOep#w2d>zbKjzA^7a1}{3r5dx=;i-(Its@|8L?tm93xZ91edR{y6*p-_-$J|Nrk|kNg1+e;oce z`~Tn70bKw8?_!U$|Nm|5aroo#$Jzh?whrL%$Kn4y@qc?wGe|KD$F09X1}{uQL85Um zcwrj$$L0IlG4^}l|E@9v0|VestfS~9EK0i~PdR z@cB12221=-zB z@Zfi^Mn*O{Z!r}4+eqmyNU zJx1e>sHiA#>eQ((0*Z@^XVihI;+u)K?r-g5d7Hfb9r#c7`IFnk9%KFHpTz%L zx`|@F)YMcUAt5o|_p##&wAInk0q@?un^p%V>h<5kda8D@GM~JiZT!C#Pfczg*@>xQ z1XOOeS;wfyK6Sp&!pKbh6TQjv+U0n@yb#=kv!-uED9;*X9JUqb9&kub3_;E%Z_$S4K z6J1|cCKKRgbSm6Zkg`T5i0k8I69B_5m!e=aVr8SNcb=ds(F;{WN|`I+;7s{bb@ zCIVq$;UAI#Ru-C?ngGqAOvfM6fqz1Na60->|Nj&CqdqoM9(5}E{sjKn+1cRIrAt%B z`dEx-+9Ka+Z*LE#n{z;XAszVJvA|UFMd$tm{-}Sry1Ih!@bDSsG?~WVi9gcCl9Cdj zp`r0p{eGfOoIZVeOpY_<2ho_|Z|cBg*A53vGWV{tXQcz{0{}+Hu}Qe7|QO<%Z(p<7eazjdlN)4osBm#QooiKeCCB9z6mm zcZy_)a;b`nis0?rx8LOpei#0z?|XT9ffFZA{Bqx)s2d6j3jf%6a3bat_kS1u$lu4r z!~h{7p)Y(Z8e3nxb`3N(Hh$9v{4V@a9-ohoZ&tBKdVqMle*OB4c>xp)pt*-Xy-dV> z;{NZzA7PJjsA6JbUto{zD@abaZrz$OhlXgJZTt~kuV23g;^N}7j{QX5{)zG6M9e4d z`}+F+un+v!`0ve|Hvo-|u`-!zi}I*WPEG*Lu}-9C;{I&nk8D0Rw~L+An~JX4IEUtq zf`WqnQS-$UwmnnTpn)0;6r_^0Lyu`->!oelhv4@dbO1w&GXtM>aP%Hy2#KeEEm`(Nwhk>N(UeQ0{Z4yce1){GH20%qQ;uD*k8=^xU~~ zKi%&q%J$^RlVd&v`>gG+;E$f$Mf&uo;=PG{Otp{V!Q|xR8S`F$1AiYMpPwH8{f@CT zvLk3t0*wiN7JsBaXfFR({Lxex{>nKN3!vwUriyd0{qf&|zkz|lSPu7B=FMi3CDH-( z{3VJ9W-2$`HRNkiei7-<_pU!P|BGn+-uh8Fq?a?z6aFpy(O6|VSx$9cUS1xksj2-| zzl!p+=)H@n+W*$MnPiOZYm>LgK7Xs;$=8uRpIpzc9RFMJNBT0|^O2Kf^ee}Lf`UJc z32G0A|JRx{on9jU|D*l?S1|n(_u}yXe*C??y>a-%xu*ZB{m0?|>AP4s{J;PG{~xvC zD7S<1{OCQ(AHDZy%KsDWKg#F)==!zQp1m{E`G52r%EDg#UJGcu3o)5HvfXfeexE)clf*P01p4Zi@%DB3PA5wOvZfT zF|q?_?g>2uG*e&xnQJ)wzaM`Tlg(!Qhx|R7cb$m!bo=PN5cK@%*|TS7RR?hR{~i1h z_Q>DQ^t{t#T|mzbAv-Xe&*$Lq|1tc3#>P&(2l;#S%x6wc&a~L0XC0^eHUxTy8a*$I z=Km+w`?LEv{Qn&OXzl>bYa{F@_igMk_Wein?i0$1V9!t7qGz>c%NOAA|8w}GXI#JK z?^|}ZXl(ea&lBPB|9<@M-MjbGHW!WWzZK_W`~F0VkUn5BpS(pe zA<}_g$ra=9pD685`;+C2J^mT|(RcwpSDBTS^+j$6Tj#{>#J)d~s_DM@gziPpexdJD z{%np2hyO%L&y0UqSQtS0`5#%)GwpeKdDHe`EdDdS^FEUwz}_Dm9Q;FcVR@M8Ia_Sq zleaf--u&UV(0gu^>p{o=ru_d@^v}jQB!lVtK2|%?m|!;A`lr=_!~grfg^FyzOn%^> zhU@pz^Iyjw@&CQwJVG`CmH%GZ{u|2u*YW?6cUfl23H%$do{Gl*I{rWUF5CCSf>X)) zpL*`UjQ@}HeQX?vwln1f{;4=mN7p|Qf8>w<#QH1WxB3(G{i!x4>Naj4CxO|L00y_< zB!H6uP69Xy;3R;Pz<*8xw2)&?xaz|d4?_k2!-W%rNnY}49Xp2qW-H#n)${L`KyPao zc&g#|pI8%a27U$B$I3>ahY|QstR{=aar{q`01khg{^R;T&i?%ubO2}n|GoatW+nVy zu+DuDs^ky!i6nk1Uinr0t;j@x?=cf_53YI`(J>nAD5S^ExpEl6W1+Eg`Y@hy+H~pD z`8@_ee~t)n*>ZX8*lCyESUJNv0>E>x=GZw)YW1=EZZ8%FzDEp!H?02_u{%#oY{ts}XrKL2{tXE)0C#pZU`Ql4*52b|ieu438~m?_Q5idz za@lz7TzN$|JpP1B^y!;mpc$0{V6cA#+}?Eu6x(}_9p|QefaN5C#R37)@%GKwxkpAx zV|96Lmj$4^4WPHfZCUJq`vw^RdYi$(5CHavoI#Sb!C3i3|58|9aO@te43Ny-m^6Sf z>1CjY_vJNgneXM_f=moVikpFkmwBKAi~tj|n`3Q#5B~=E0-!M}dW_E6$_|itD;OBl z-<%cxtx1K!a6={Nf;wQd=EfKN8$kZc-2%YJ&Owmm_!QW0*M)Kr{-Vsc__tdp4qoc{ zg3g-v0E~`+%ItdZNI3xL6N-O7|4^?#rX-BJBkZ91 zM_{yC9n8dkk)=D7>oE9G0iP|F4FrZOWWTB#%RlUnz>LXi?0T-T(-R_UXcT~ZA`iZz z5tTuG!Jp$As0erlM*I6fZDl(!TB|W5|Aun}f#05MpgQyg7=qu%?flpc;!I+I)n+x= zk3QLTEdS`&Nt&uUK+)q@V7R|~jE9$z?|{V;LGVKNKIpHl89P_{surY}g@aq`uaEct zp`j5_o>Dz#Ti}l!p+C^m(FY2j=7FwvpYCgH7zD-?>QnNM_zORx4C@~Tc^NH0f9|Kg ziO%095dn{dOh7|gHW(fn1of3|AWS0^+*}W~ zQq8ezSpJb^PgL**eGMPR=&vbk26uKE1IN_@V4%KkjQ5HE%=X!j^I!a?0c2VQfZ^Uw zFaj0nRZt1=-KPs0-(?K8%%>(3Pdw~0l^_D#uTfdRfCuvjS#EXd`dZT%ES7%vhAmgI8a z_DYD=|J$p{{%;&3NMrJ)TaeXJkmy$g_4C4*&cD!d0T1NvgIkL~(KE3;+W!&$C*O;X zC*qIw|C7rh8=Y(N0e}`3Kp#Ob2Xzv&Vx3?I6f%A0r{|WxF zZJRC<1tz3l+feNF@7d18KhpOidoQT%qaeiKIpqJ7kDIC9U*$hwk36W$r~pN9)x*Fz z3)1jASEn_Spe{KRRKKbK)~x1VwPi~#2Ers9fj6%$&?C6`)%D4={VM;H>-)DIr~_yJzP5iueS@GTrTB}rGN}Ok=sLL$>~VE+ z(GS;E^`h_#da!k&ZFxc-nCbe&vXl4UrFAj){wKfxFw?u!Kg#dq@)LPQ-`qgIg*|zl{JWeJ z`JcEyk$?2vr^)qTkJ0zuu<${A*}vd>8(c?Gvg4(S^0y==ewUf8u@UUi4e36TkmuZEgL(yy+rK4sgJ?H~3YWTVh`Zzke`z4oL0BcG_FqcdguSeuM~ zm+Jr8yB6Rqsw>P`6{U8RmX6v{u~uuXola}*)W>w{jBNq6*r{!SK!5}dC>T+!0fL6S zNCF99AORsUL6QI_%(UOld?_t0^}xim+{(Xb(IQ8-M`=r# z;}pT&)%H-*aVtOnM>TlxU?abteDX=--@bZUZsg}bY2EyrknN#f=DN}z>X`W-FDYxf zZ!Q1Zwr%rhpGg}S80gVgJC&a{La9HUpT98M!~Fbw4;`=%>CEL;ezwovY|_#0CFN$C zPUPo5viUCzfAZSBA3AiX(e~*0IsR~a>GA#LKieMWvmG9JHgo1o~s zUH&Okrr2U;zeAf?!qcD6wv0C0ywUOh(8SC#Vs+ly0@@j~((<0^=xt$l$WI%0ZtY@A z-(aT${rgYXKf~Va;73PCn|+=&j(*=A^4rPKm1jLwe%h{eBNy#d$Hc_A>bsf##gLzE zy`7V}2&eskUUuBbPuVwZ+GKpEyZvuiSLNrJ?_yn@k)M5UMMZ^2edJhp(4aw%%1=*~ z-${SWd@nCA_mG`Bd@C!e)dh)d}keGd87{54{_ec-&nq<%Flmwc*{HH zyH$3XgJ7Q{^@z5+Sr>fipr^{uf5h`2Bv!}q59g#rM*7z8PMHhkJL-UTi>>L%J^yi_ zr=^F3f`V-0al9yW-PQg{`c8c7_m;o8YbR+srMcYlTk~G}BI`V+Q+eFdU2ge(jWP9l z;8rfD^cPcpmRq+@^4rem_{(j2Zt2~Q@x%^5umAt40osZ9nQ~*5Gwnp&`M+x?;ZeD&mgJ)C}lh6Eu=p_&%m~F(5om>?|2S3=h1MidpR5F_lMzp>rt!@E52y>lLwB+ z*63`c{yNb}^KkJ-e6AYYh(6C^!7XZ^qdG^tExT6T569+b6OFS{Cz?OU@@KNplwX1~ zigwn3SCD>JunL_+#alH-It@$SR(I-L+1=5oP0qnrJd5~?IP70uh(k@M)j1RGyj|Y_ z>_{oW8^4V;&zSnsKhH*GKJYixuPnvclc!KuQinNrP4kPtE+t#xXhYI3;}LmvfNT77 z75)_uhobHLIi&qH!{A4pG3t!lj-+gy{`5E+)mg<=AsOndcl&uXyYkcYb}>$!Jc|tx zYY_jv=goAO7WK~_JK~CoO8-Gh|0hiS6aP7dKjEH8BaW&6?}lB_|MCxwcMVH(JLsSI zqZE(NDyy((%b^bEnq#jTj=~XfIJUbUpB_Gq=o=>+=Pnf-^J4$|&Yz-iw59={)V84L zr7V^I?dKu|KZy&&*PIU98qUXvxX+1wXPngzHCGMz%aA?5I=dW9~FsnU$tT0uM$k%#at7Bm4hSDR8oo7 z=2mQ&RbtpTu+u-&h*k9Ye~H7V@7Lk@KTl%8gL90usDGYBt$(xJ$miqDr;z+m9Ck%2 zS+pxBG~d9_+2Y-qW$JwJS)6D-gLNDcT?-&Dd{_Li~50R%a^P&%Imm zlkcvXi*e%kSBO*RYiFstR5WpkM>!CD{_qQ(_=2D9k3189@!ij3-3u9ry{X-1f;{)< z+u>g{a2(psv?706Ne4c9dT#O8Ey+WZ`aX#0bD>V?>2)St6}|+`b%&97?@SXb+rV`p zuN!tec;?$%x^D4%OXqSu@5SGJ;~^(`+N=Lw{W~cq-e|1lXXyhokf8dU%jQ(SmO$qa z!}jEM8#G$iZw5Ih&pBy-&TdZCUmU)dH87K*3hs}zHDwe0oC}vr@HaFxm~kX-lN!JAy^f!2u@XmoKI_UQ z__uD|+F=h+TwI*VkNAn5c!Z~5NJ&ZQu&!EEROEqQ;xbNibF<+XW_r3#+{)qxztEB= z<#CFiv=Xv()f_pKzPg!U>Q=i@9KXBlHsWaj01V8rybB}@O zMtttI(f=teb<1fv((y~0;#>7!RaIr|zgxe4y{R+G;1B=7g9kBU#E1^qg%9`4a<4Db za$BDTKlffpdgAN&xi9&tr=Buss5AY4q`vTT4`pa*Xos|ghxn}1@-JOta$29A;6HTe zP=|fR)F<`oOaH8|2?+^)u~P=_-{ihqxAoZ{e(v+-zpq74x*rk}V(bI9(?9>Uo0F5% zp-s@^Tf?l+JS!me%GWx))DK_yqoShxo;l%}l=<`LcaV?!Te#1evWc_X%T6Bho<8>m zNjY-TrV4)Uzp?7W$v>f)?{<5NrT-OO(w{bMS_d9%mvkCE+*SNmd3ewL<95%j&n^aj zC;fph{aZ0{KYm$R8ODws>sJQ1_?_rl%DnD7#ZT;Yb#+Ewvk&tp!==X0aj#Y1a!>5_ z_4NjJ_Ae}>|4`>3{2c#tZ@%tEj~;F6o%p4UQU;NS zGVn~J9*^PT;$o9VXt~GVN>@`;W6(+3df9do7F`MtZ@!HAB~7*s-e^1Xyu0yR+cN!| zq%(M}aXO2i<5eflZal?uW8Ykb7YI{)cbs06leOk9G_lR=lKCK&i=02^e`Nc?o z__a&wG9GESiOn{unYymIlKBis_#f?9((zBgZ>xXH3@TW^IU7!^URz6XDS=$ zas7iaPub0Xe>rVsk3reXX-FTGgrosMct52CD@HECdy!dq<2UhG@%vX%Jfi@!uOEdE zGB;uFEupB+D8;+M$@s8%pINSET{lLpuU@dVY2_cI)`SZK=b>>^4ORtbV)329hCTO) zKI71|b_-UA=AuN|RzJM=7+(L$EBI_jHC6^^p)52RA5|Pwc*o$pvOAo5Z@9AKeHuwW zoQl@{2ax!qa0A1e_fJM+RRfB{azR_VR{kwpcA+}|L&T_cdg_V%c?vr6x`{YkT50fK zH*OBqm=#Ls_11n z(Q*ng115Tu{{&^{w|wd{d|cUpjK}Aj{12?J!IxiriS*ya;^^*uIHUGaygR+XkiW5V zKh7R&MSbxe9NpW9radi~cT5X^nLqO-=$=bGGwOAJ!GOysl9vmdOXX`%?0HYneBYqePI50`~J1# zKWx}A+ccRMI*-cAN<$~qOJ-)K`Hph)8J)g{=u7_r0Rd)wod<2Tc(dKW`X}{6F9Txl zhINo~(|Ie0BEKE~@#DuE>$n*i8MYYw@%P44*Mso4u0OFZ)1H>h|4_eHJzPxw%rn}8 zqGP#lX=yR*4l#1wg&2f}{?45{P5skeh`eKb=8GHoB_DNPFSB}EsMGigJK@iMgYwxq zeNKmMh#ifuXWrT!H9c@yFV0h_X$fPl!knkLvg16($xn{qgY>dax#sGF*k97VPrWl^ z*^21ZuHy6iQRgG^lWq<{))TX_AuJOs9*akoavNSnEq7bm|IJ%qm1w zzp+^MXe8$SU@|2B=GRtW*^mV6NG?RR(naa?Y;2yh4h==yv9F{W^+h{Sm9z$n@0*Ie zacOw-q3PHXU!>A2GV#y4J_zs4&O_vtV~}{`IHcYeuEGJvp5VwUN1)=hY{c9Ug5t@U zAT8w({<=(V!WSd{sg_oJRIn4fb1O|(U%1QT*`B;grHfstU0nsfW0>yf-Xlgc$2zca z<3_{w68mG;H`dF7f&$|i`*=R%+Kt_qiSgMVvQOYX0`_IB^Rz+0XN}6H71vJK_Ha#; z^-;g{_|?_b#(F8&ZYBQi-Mb-U5BB5SLqI%oG5*SxD-B+>4@RD}jUZu;RbpdfjpwxG zL|V30a_R9Imur-IUqk#HTksvzqHe7GX*-g(Ng|XDCAPyHXL7vAXIx|Fc$s0^R3ktA V;yv{$j`vJo?ybHazpIVZe*kC8JfQ#p literal 0 HcmV?d00001 diff --git a/NoteWidgetAddIn/Properties/markdownflag.png b/NoteWidgetAddIn/Properties/markdownflag.png new file mode 100644 index 0000000000000000000000000000000000000000..d92841814ed37ee7df686fd157ce2b89cf71d77b GIT binary patch literal 2872 zcmai0c{J4T_kSZ}GPberTe6LirR<3*j4Ta}C0ik68Cl0Z*)k+4`;w$L31b;#k5nXE z36V9QK^R6u;)A}^IluG!?|Z)YoO|zio_p_k?(@9PbMGZsTbi)53bO(Lz;0%WMAJ3? zFGC@8*=um)BVC;cHZrq?(kUA1kwRae3^a8J27oZpzsyka2De7vO6%u|U z$P@64^zyl-?2h$++Do#hTQ&b$jj{gzo&h0%F*YE~GbqH?*Hc#q@=KP3IJH6%#astaYdBbxIkXA5DRsSB=9(Dz8%I@WL-npfv_lA^HrrM zSj#r&!C{aTsk=~18G>M?q}18Iq=k_3<|VBrF|TPxqu9HK&;{%Lvao5(;%&}~rZ7h@ zotiK~3R~E8W%fFS;4yy;e*hVr-JGLP0{UtDw9Sb5z5EXBT+H6A1dHl>LHGM-|ECz- zlFz@QsKPUm2OpITZ#Z}ha=>{e%1Ri zdGWTNDzHNM!0fcy?CDDQ;1UB3JC zXQx>lv_+=iifkc;|FZ_=(v`*G@OW1Ukn+M#fv;Y;#8l=spy$+`ReoZg4FJfMwzsRY z4Z*B08Whk-PJ{2a4`8S;9&voQA4Jk}o-ASJ3Y7wVT{0cI6F3d>?3jEfiSNoS3agV% z81EX&;VaacWw;5oK%It-s7?s<9*0=N^shwA5`$v9{pdfj`_0($1@&$!Rh2_r&%463 zow)8=unGgS%6+D-04FaDfv5NaUrP{FP+a`|T_%?5WC4-nPwJlp+K6!?hS?6x#>U1o z`~3MFz_SiZbrs#%!xr*ILu3a1%x~}G%GV=Lr?r_|+n|kSp&Axr z#8p4=O9qfg;`=`QYGjv$U+T+PBImj`bGM-3qPCW^?|~RivBo!N3j(N~gDN|<;Llud27q6ivuSp&G2=_sM2m8!?i$VR z@!=xvgmt1w`)XgYt5#PL!{?TzA##*WEq0hO?|gJ9fA>tEdN=Q1wxcp|ad>s!D|;I7 z`Y3E<`iT;&0q}kMH+f9^{54zKr&U!Scf;fg<7*j~M@lj%-(I!1<)k2`Q~H*k3>!R7 zLi`Ju=P32G2Cs}xPTEnMQ&Uq%XJ^wzupOW3bviqM?2%w*O-)U2EOtbAY1+Zi*;x!z zZNF&hoX-Vs4wy|%f(ht2Vr^`AHoN`}Fj-e>jG!%-HZ_fF43CrW6B8KQYx#2%C8W^x ziPE;V>Fr1YR5xs+d+7Z925vS6e;%hL@fx`&pZap@3D zPfvd^Sttu4t*kgv=H{@8WS+nIjgKegt9v<~+zN@2c>4VLiF$iBGP!&N?-=&+%&V4$ z(IQP>ejObhF6ar?X-fk~N5?w19!5mzJupiJ*8sQ0V3PHterYwJR8&;@HfP(fqQ4I# z;x}8CICMGN+g`S{33KXE@!6vnpi<|U#5Yf1Y;D~piOvxe`11<#kFg5fy!_VbX-6g3 zu9@+3L&&nLdfRV#Fh+lBe5P+pAE+#BW2o`WusZ*5%|+z_7GrhpeH?>N^uO)DRr2=r zMf5w$3XGLo7+YCoWIK#nqiQ%I30vR=>Y-!zXVARZmOS&N1K7?!SYpiu+0QdG zexdVAwyJ{Bn`@jg!P+f!P(H`)JiC;pJdapq30@wokK72IY4H457vwqNb!+TcDG`^L zVi3OfP~{e|@TYIbTZ2{=r-(p&nwt92K32E3cDvfKX<+KK4CWUcNOGu~JNI6DfGbam3G z#y94H=kn8mfq{=vCw{>6Xv;%1oijFzfr8sOQS?B3)Anjv#?4R9E@6zU%oQwLE0?N_ zyKyi9Wn@&8uCRzmz2B6YRZ#yWI`uSzxysI|bRZF>ar--CR)s13s<0h0+rzN=n7z`{ z(w=nkEhx~*Xuk!aGR{5R1V^M zo;ti>92F%XkG-1$=EWIhb*10fSm`He2QUBQY-M6{4`i-GuW2iQHP>@-5c#K%9&v|+ zhr3TV`e;wq-&wkBUXhEcoCLG(wC~c`tlh|Da>~1#@`?>{|C06hW)d`gC+tt^>+0xC z8zRfXzEOMGs8@;1gw+d{vX9En4>1OG?qdArI;JonA0Hp4HcOV?sa`ZT?vykOx4fk> z7$VsLzl<64j;Tb6KGpk)5}9-6Wlfrc)WO{=ZU})T4*kvP?XgFZGoh2tn1UE%Xy#s-6}^H2hDZSh4WKSa zv>obZTwZnEB@@lT^t;Q!Nrw9a&eHYTwWNcCNW@T#s*X-ua*6?|r#`i3Q&kpn{ORFVvr6YIbNMGNj36v3u9Nk|%shgVtRcT$ntmStw$5RisXU(4_ za_NRT*S=Ya6Z*$p`t|_XY0?52;xf65Wx&AHXLm2?8+J%KBIP3PD)*I zCHmdla^b#&ECJD#?5N6lMesegR9`t!Yu(}IIjGce4hj@z>&3A<9KS~<+ABdUNE-0h z3W;Ag?H}d-UgLVm&jy*dK{?N9Uqw-J(Uvd6->@X~lrXJoq>;YvuK-`Bj(nUE(c1JU zL`B?BiDg}=MGyG9tUQJ(kYT9G=!%Vzl+_ywIh%fi=*3y(`rL0vWXCtcDtEZEzb1G?V8&5QFExZg3wo0WjQ|F8xJ-I6&k!Vq?V3 z$!ti&$ITV|CDej?n7TcUQY@tp9C993ByqhCLr91N%BQ4H39_A21Z5)~y-ZR2#^-5^ z3=0g>2QpmHYKZFb1SLF?>x>Ket=>Zvm?QW2L)r(ApRSd*iZq-0jp^(wvL%)vdY-Do g`QJynuO7P>x;uzq(}K)<`Wy?GU9v zL)ykfiHq8WiFRXRbccxxHJTU~Cd7p<43g?f7jCpjG=bRKXi^bcKiX)pg@6OhNcotV z`qtwA`v#m3@4MxwvFPpWQjx~?0McV#uzom z#BM93ARfEAtk3oh>mSqcEkmsJoVINrRMnQLe++|TGjzW*%*=ubTb8xyatVOvdCk7> z9~P17!i1_uL?m)yYLO%F4&zpq^UZ4!n!{Cb-}fJPUH8}j1@JuYQB@rT+?xfh2g&7f zkA*^^-);#o#*6|TD_(}zKR?e`V>8Sxd8n?xVE>&V&c4-6O|U#JA`dx^Gr1AK2HF6Q zz5hL@FV1tcV-E-FtJef6FfcN~l1bCk*+fmS93brb{tL#Kdiu5R%k#Q=EsGriXDGJD)bjbOS>+K%E-^ zAbQnMy{D$Q;O8p~oIHKGC|(e$Z8<_FIagBe^zt-`%OkjromiIjKoJmWYrw56=cR#j ze0ZXhmWKQp9NM>&AKvcfzPoDI2syi2adx$q01}gDNH0(455xBZu-a(#wGMsH9pb0I z7HIE1#hFX<#YH!YZ`N#pY%0$2u4cOK2{SYvrTLDVw!~(v%NX;j4dBHuacyCOy&cc< z;u9^mLmUx_01><3$Rwi0$!sb{eEieRtNK|0X3xGyUF%a+)a{?O*NaO<$I$Gx%>!0V zEStcNy{PIy2|#lh%=|5%m<_F}p&gMjUqt##o@+1m`?j)2gkVEEBJ!={IFls+GdsR@ zaiC(yKFTU + + + + + +