<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hollow Man</title>
    <description>The latest articles on DEV Community by Hollow Man (@hollowman6).</description>
    <link>https://dev.to/hollowman6</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F730480%2F832999b0-550a-4bc0-8f5a-8dda8d26ed4c.gif</url>
      <title>DEV Community: Hollow Man</title>
      <link>https://dev.to/hollowman6</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hollowman6"/>
    <language>en</language>
    <item>
      <title>My Igalia Coding Experience 2023 I &amp; II at Wolvic</title>
      <dc:creator>Hollow Man</dc:creator>
      <pubDate>Sat, 17 Feb 2024 17:46:10 +0000</pubDate>
      <link>https://dev.to/hollowman6/my-igalia-coding-experience-2023-i-ii-at-wolvic-1ned</link>
      <guid>https://dev.to/hollowman6/my-igalia-coding-experience-2023-i-ii-at-wolvic-1ned</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RZtEgtVE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hollowmansblog.files.wordpress.com/2024/02/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RZtEgtVE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hollowmansblog.files.wordpress.com/2024/02/image.png" alt="" width="776" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Igalia/wolvic"&gt;Wolvic&lt;/a&gt; is a fast and secure browser for standalone virtual-reality and augmented-reality headsets. ex. &lt;a href="https://blog.mozilla.org/en/mozilla/update-on-firefox-reality/"&gt;Mozilla Firefox Reality&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project summaries
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Develop VR Browser, refactor Android deprecated methods&lt;/li&gt;
&lt;li&gt;Address user issues. Implement UI, graphics, browser, and openXR related features&lt;/li&gt;
&lt;li&gt;Contribute to the majority of the features available from v1.4.2 - 1.6:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://wolvic.com/blog/release_1.4.2/"&gt;Wolvic 1.4.2 Released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wolvic.com/blog/release_1.5/"&gt;Wolvic 1.5 Released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wolvic.com/blog/release_1.5.1/"&gt;Wolvic 1.5.1 Released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wolvic.com/blog/release_1.5.2/"&gt;Wolvic 1.5.2 Released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wolvic.com/blog/release_1.6/"&gt;Wolvic 1.6 Released&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  List of things I have done
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PRs opened/handled
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;(merged) #773 &lt;a href="https://github.com/Igalia/wolvic/pull/773"&gt;Fix build with JDK 17&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #787 &lt;a href="https://github.com/Igalia/wolvic/pull/787"&gt;Fix and Check warnings / deprecation notes in the current build&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #796 &lt;a href="https://github.com/Igalia/wolvic/pull/796"&gt;Fix deprecated android.inputmethodservice.Keyboard and keyboardView&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #811 &lt;a href="https://github.com/Igalia/wolvic/pull/811"&gt;Fix and Check warnings / deprecation notes in the current build&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #812 &lt;a href="https://github.com/Igalia/wolvic/pull/812"&gt;Fix deprecated android.inputmethodservice.Keyboard and keyboardView&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #814 &lt;a href="https://github.com/Igalia/wolvic/pull/814"&gt;Fix dependabot.yml syntax&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #820 &lt;a href="https://github.com/Igalia/wolvic/pull/820"&gt;Upgrade Android dependencies&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #829 &lt;a href="https://github.com/Igalia/wolvic/pull/829"&gt;Initial flow for mainland China&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #831 &lt;a href="https://github.com/Igalia/wolvic/pull/831"&gt;Use androidx's PreferenceManager&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #621 &lt;a href="https://github.com/Igalia/wolvic/pull/621"&gt;Add some dependency conflict resoluton strategies&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #838 &lt;a href="https://github.com/Igalia/wolvic/pull/838"&gt;Fix keyboard icon displaying&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #824 &lt;a href="https://github.com/Igalia/wolvic/pull/824"&gt;[l10n] Update translations to Chinese (Simplified)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #843 &lt;a href="https://github.com/Igalia/wolvic/pull/843"&gt;Support per-architecture dependency substitutions for Gecko&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #844 &lt;a href="https://github.com/Igalia/wolvic/pull/844"&gt;Implement POST resubmission confirmation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #848 &lt;a href="https://github.com/Igalia/wolvic/pull/848"&gt;Homepage bypass cache so that it can work corectly after a language change&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #816 &lt;a href="https://github.com/Igalia/wolvic/pull/816"&gt;Bump com.android.tools.build:gradle from 4.2.2 to 8.0.2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #781 &lt;a href="https://github.com/Igalia/wolvic/pull/781"&gt;Remove WaveVR build dependency&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #852 &lt;a href="https://github.com/Igalia/wolvic/pull/852"&gt;Fix several issues related to Download List&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #853 &lt;a href="https://github.com/Igalia/wolvic/pull/853"&gt;Use left alignment for the download Confirmation Dialog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #854 &lt;a href="https://github.com/Igalia/wolvic/pull/854"&gt;Modernize deprecated setSystemUiVisibility(int) and related flags&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #855 &lt;a href="https://github.com/Igalia/wolvic/pull/855"&gt;Make keyboard follow the system locale if never manual select&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #856 &lt;a href="https://github.com/Igalia/wolvic/pull/856"&gt;[HVR] Make PlatformActivity inherit form Activity again&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #819 &lt;a href="https://github.com/Igalia/wolvic/pull/819"&gt;Bump net.lingala.zip4j:zip4j from 1.3.2 to 2.11.5&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #859 &lt;a href="https://github.com/Igalia/wolvic/pull/859"&gt;Ask OpenXR runtime for available GL formats options&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #860 &lt;a href="https://github.com/Igalia/wolvic/pull/860"&gt;Replace kAverageHeight with XR_REFERENCE_SPACE_TYPE_STAGE&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #862 &lt;a href="https://github.com/Igalia/wolvic/pull/862"&gt;Fix Android tests&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #866 &lt;a href="https://github.com/Igalia/wolvic/pull/866"&gt;Remove overlay extension support for Pico&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #640 &lt;a href="https://github.com/Igalia/wolvic/pull/640"&gt;Ana2k/date time picker&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #877 &lt;a href="https://github.com/Igalia/wolvic/pull/877"&gt;Implement DateTime picker Dialog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #878 &lt;a href="https://github.com/Igalia/wolvic/pull/878"&gt;Fix to keep the selected options for &amp;lt;select&amp;gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #876 &lt;a href="https://github.com/Igalia/wolvic/pull/876"&gt;Meta store fixes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #879 &lt;a href="https://github.com/Igalia/wolvic/pull/879"&gt;File:// uri navigation support&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #880 &lt;a href="https://github.com/Igalia/wolvic/pull/880"&gt;Use getNonAutocompleteText to fix awesomebar&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(opened) #881 &lt;a href="https://github.com/Igalia/wolvic/pull/881"&gt;Reorganize Libraries and add search UI in panels&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #882 &lt;a href="https://github.com/Igalia/wolvic/pull/882"&gt;Support using maven GV from the release channel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #883 &lt;a href="https://github.com/Igalia/wolvic/pull/883"&gt;Continue upgrading some deprecated methods&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #885 &lt;a href="https://github.com/Igalia/wolvic/pull/885"&gt;Fix Language change issues when change language in Wolvic&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #892 &lt;a href="https://github.com/Igalia/wolvic/pull/892"&gt;Use geckoview-nightly by default&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #893 &lt;a href="https://github.com/Igalia/wolvic/pull/893"&gt;Migrate from org.mozilla.components:browser-search to feature-search&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #895 &lt;a href="https://github.com/Igalia/wolvic/pull/895"&gt;Only pass valid URIs to loadUri&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #903 &lt;a href="https://github.com/Igalia/wolvic/pull/903"&gt;Remove duplicated code from HandMeshRendererSkinned class&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #906 &lt;a href="https://github.com/Igalia/wolvic/pull/906"&gt;Modernize deprecated CONNECTIVITY_ACTION in ConnectivityManager&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #908 &lt;a href="https://github.com/Igalia/wolvic/pull/908"&gt;Fix a crash when retrieving WifiInfo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #910 &lt;a href="https://github.com/Igalia/wolvic/pull/910"&gt;Add a null check to getSignalStrength()&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #912 &lt;a href="https://github.com/Igalia/wolvic/pull/912"&gt;Create FUNDING.yml&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #913 &lt;a href="https://github.com/Igalia/wolvic/pull/913"&gt;Fix opencollective funding link&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #914 &lt;a href="https://github.com/Igalia/wolvic/pull/914"&gt;Fix white flashes in several (heavy) WebXR experiences while in immersive mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #917 &lt;a href="https://github.com/Igalia/wolvic/pull/917"&gt;Upgrade Android Components to 116&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #918 &lt;a href="https://github.com/Igalia/wolvic/pull/918"&gt;[Chromium] Pass the correct URL to onPageStart&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #930 &lt;a href="https://github.com/Igalia/wolvic/pull/930"&gt;Copy search engine list from upstream and add yandex when Russian&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #935 &lt;a href="https://github.com/Igalia/wolvic/pull/935"&gt;Fix a crash when drawing hands before updating mesh in HandMeshRenderSkinned&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #936 &lt;a href="https://github.com/Igalia/wolvic/pull/936"&gt;Revert "Modernize deprecated CONNECTIVITY_ACTION in ConnectivityManager"&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #946 &lt;a href="https://github.com/Igalia/wolvic/pull/946"&gt;Fix disabling address bar auto-complete feature in settings&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #947 &lt;a href="https://github.com/Igalia/wolvic/pull/947"&gt;Implement Find in Page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #950 &lt;a href="https://github.com/Igalia/wolvic/pull/950"&gt;Fix restarting Wolvic&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #952 &lt;a href="https://github.com/Igalia/wolvic/pull/952"&gt;Use red color when no search result for find in page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #953 &lt;a href="https://github.com/Igalia/wolvic/pull/953"&gt;[Chromium] SessionFinder: fix a startup crash&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #954 &lt;a href="https://github.com/Igalia/wolvic/pull/954"&gt;New approach to handle remote environments &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #958 &lt;a href="https://github.com/Igalia/wolvic/pull/958"&gt;Open the feedback form in a new window&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #959 &lt;a href="https://github.com/Igalia/wolvic/pull/959"&gt;Some minor improvements for Find in page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #960 &lt;a href="https://github.com/Igalia/wolvic/pull/960"&gt;Allow open new page without interrupting video playing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #643 &lt;a href="https://github.com/Igalia/wolvic/pull/643"&gt;Workaround for YouTube videos&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #961 &lt;a href="https://github.com/Igalia/wolvic/pull/961"&gt;Fix Youtube captions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #966 &lt;a href="https://github.com/Igalia/wolvic/pull/966"&gt;Fix WiFi Icon when starting Wolvic with no WiFi&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #968 &lt;a href="https://github.com/Igalia/wolvic/pull/968"&gt;Bypass download uri cache when user tries to download again&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #969 &lt;a href="https://github.com/Igalia/wolvic/pull/969"&gt;Fix 3D Side-By-Side video playing in curved mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #971 &lt;a href="https://github.com/Igalia/wolvic/pull/971"&gt;[NoAPI] Enable on screen rendering&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #972 &lt;a href="https://github.com/Igalia/wolvic/pull/972"&gt;Refactor CI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #973 &lt;a href="https://github.com/Igalia/wolvic/pull/973"&gt;[NoAPI] Fix control panels&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #974 &lt;a href="https://github.com/Igalia/wolvic/pull/974"&gt;Remove Find In Page Item when in kiosk mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #978 &lt;a href="https://github.com/Igalia/wolvic/pull/978"&gt;Upgrade R8 to version 8.2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #979 &lt;a href="https://github.com/Igalia/wolvic/pull/979"&gt;[NoAPI] Enable WebXR and other fixes to the native lib&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #980 &lt;a href="https://github.com/Igalia/wolvic/pull/980"&gt;Add back Find In Page when in kiosk mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #982 &lt;a href="https://github.com/Igalia/wolvic/pull/982"&gt;Select tab when opening URL foreground by intent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(opened) #983 &lt;a href="https://github.com/Igalia/wolvic/pull/983"&gt;Use versionCodeToDate again in Settings dialog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(opened) #984 &lt;a href="https://github.com/Igalia/wolvic/pull/984"&gt;[OpenXR] OpenXRLayer move Destroy() to destructors&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #997 &lt;a href="https://github.com/Igalia/wolvic/pull/997"&gt;Cancel find in page on navigation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #996 &lt;a href="https://github.com/Igalia/wolvic/pull/996"&gt;Improve detection of URLs with long gTLDs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #999 &lt;a href="https://github.com/Igalia/wolvic/pull/999"&gt;[OpenXR] Use XR_FB_hand_tracking_aim to get trigger pinch status and factor on Quest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1000 &lt;a href="https://github.com/Igalia/wolvic/pull/1000"&gt;Enable starting with passthrough mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1004 &lt;a href="https://github.com/Igalia/wolvic/pull/1004"&gt;Enable to use system trusted root certificates&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1006 &lt;a href="https://github.com/Igalia/wolvic/pull/1006"&gt;Replace Manifest's attributes instead of the whole node&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1007 &lt;a href="https://github.com/Igalia/wolvic/pull/1007"&gt;Enable voice input from keyboard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1008 &lt;a href="https://github.com/Igalia/wolvic/pull/1008"&gt;Add 3D top bottom format support to VR video playing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1009 &lt;a href="https://github.com/Igalia/wolvic/pull/1009"&gt;Add 2D option to projection menu to allow exit to full screen&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1010 &lt;a href="https://github.com/Igalia/wolvic/pull/1010"&gt;Move page loading progress bar around the refresh button&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(opened) #1012 &lt;a href="https://github.com/Igalia/wolvic/pull/1012"&gt;Enable desktop mode as the User-Agent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1014 &lt;a href="https://github.com/Igalia/wolvic/pull/1014"&gt;Make voice input content scrollable and stick to the latest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1015 &lt;a href="https://github.com/Igalia/wolvic/pull/1015"&gt;[HVR] Do not request the WiFi SSID for mainland China packages&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1017 &lt;a href="https://github.com/Igalia/wolvic/pull/1017"&gt;Improve some UI user experience&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1018 &lt;a href="https://github.com/Igalia/wolvic/pull/1018"&gt;Use horizontal layout for DateTime picker prompt&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1021 &lt;a href="https://github.com/Igalia/wolvic/pull/1021"&gt;Fix several issues related to seek bar for VR video playing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1020 &lt;a href="https://github.com/Igalia/wolvic/pull/1020"&gt;Move homepage URL to a resValue in build config&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1022 &lt;a href="https://github.com/Igalia/wolvic/pull/1022"&gt;[HVR] Fix flavor detection when deciding about requesting SSID&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1025 &lt;a href="https://github.com/Igalia/wolvic/pull/1025"&gt;Add option to clear all user data&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1026 &lt;a href="https://github.com/Igalia/wolvic/pull/1026"&gt;Add back the mute/unmute control in VR video control&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1027 &lt;a href="https://github.com/Igalia/wolvic/pull/1027"&gt;Fix Youtube video pause when entering immersive mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1028 &lt;a href="https://github.com/Igalia/wolvic/pull/1028"&gt;Allow exit find in page mode when we press the back button&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1030 &lt;a href="https://github.com/Igalia/wolvic/pull/1030"&gt;Fix Chinese/Japanese keyboard typing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1031 &lt;a href="https://github.com/Igalia/wolvic/pull/1031"&gt;Use context.getCacheDir() to store unzipped environment files&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1032 &lt;a href="https://github.com/Igalia/wolvic/pull/1032"&gt;Allow YouTube playing different projection types of VR videos continuously&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1033 &lt;a href="https://github.com/Igalia/wolvic/pull/1033"&gt;Fix voice search default language selection&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1034 &lt;a href="https://github.com/Igalia/wolvic/pull/1034"&gt;Upgrade Android Component to 121.1.0 &amp;amp; AGP to 8.2.1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #259 &lt;a href="https://github.com/Igalia/wolvic/pull/259"&gt;Do not instantiate the Runtime in crash reporter service&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1 &lt;a href="https://github.com/Igalia/wolvic/pull/1"&gt;Added INTERNET permissions to the manifest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #734 &lt;a href="https://github.com/Igalia/wolvic/pull/734"&gt;Change the window distance&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1036 &lt;a href="https://github.com/Igalia/wolvic/pull/1036"&gt;Set tray date displaying format without hardcoding&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1046 &lt;a href="https://github.com/Igalia/wolvic/pull/1046"&gt;Implement audio engine using Android Media Player&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1047 &lt;a href="https://github.com/Igalia/wolvic/pull/1047"&gt;Allow jumping to the video start/end by clicking on time labels&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1049 &lt;a href="https://github.com/Igalia/wolvic/pull/1049"&gt;Updated App Lab warning message&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1050 &lt;a href="https://github.com/Igalia/wolvic/pull/1050"&gt;Enable drag and move windows at X &amp;amp; Y direction&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1057 &lt;a href="https://github.com/Igalia/wolvic/pull/1057"&gt;Fix several issues related to VR videos playing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1063 &lt;a href="https://github.com/Igalia/wolvic/pull/1063"&gt;Enable seeking VR video through controller D-pad&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1064 &lt;a href="https://github.com/Igalia/wolvic/pull/1064"&gt;Remove duplicated suggestions in awesome bar&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1068 &lt;a href="https://github.com/Igalia/wolvic/pull/1068"&gt;Enable haptic feedback for controllers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1071 &lt;a href="https://github.com/Igalia/wolvic/pull/1071"&gt;Improve Device Name in Firefox/Mozilla Sync&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1072 &lt;a href="https://github.com/Igalia/wolvic/pull/1072"&gt;Rename Firefox account into Mozilla accounts in translations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1073 &lt;a href="https://github.com/Igalia/wolvic/pull/1073"&gt;[NoAPI] Reorganize the functionalities of the buttons&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1076 &lt;a href="https://github.com/Igalia/wolvic/pull/1076"&gt;Generalize pointer scaling and color change during trigger event&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1086 &lt;a href="https://github.com/Igalia/wolvic/pull/1086"&gt;Make texture scale changeable by display DPI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(opened) #1087 &lt;a href="https://github.com/Igalia/wolvic/pull/1087"&gt;Enable YouTube double captions to fit 3D video playing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1091 &lt;a href="https://github.com/Igalia/wolvic/pull/1091"&gt;Properly set the Quest3 device name&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1094 &lt;a href="https://github.com/Igalia/wolvic/pull/1094"&gt;Add break for all cases in setting device type name&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1095 &lt;a href="https://github.com/Igalia/wolvic/pull/1095"&gt;Remove Khronos OpenXR patch&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1092 &lt;a href="https://github.com/Igalia/wolvic/pull/1092"&gt;Use Khronos OpenXR headers in OCULUSVR builds&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1099 &lt;a href="https://github.com/Igalia/wolvic/pull/1099"&gt;Select 90Hz refresh rate for Quest3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #1100 &lt;a href="https://github.com/Igalia/wolvic/pull/1100"&gt;Always bypass cache for some specific urls&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1102 &lt;a href="https://github.com/Igalia/wolvic/pull/1102"&gt;Bump sharp from 0.30.5 to 0.32.6 in /tools/compressor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1104 &lt;a href="https://github.com/Igalia/wolvic/pull/1104"&gt;Enable word auto complete for Latin keyboards&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1105 &lt;a href="https://github.com/Igalia/wolvic/pull/1105"&gt;Increase logical size and resolution of Web pages&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1106 &lt;a href="https://github.com/Igalia/wolvic/pull/1106"&gt;Revert "Increase logical size and resolution of Web pages"&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1107 &lt;a href="https://github.com/Igalia/wolvic/pull/1107"&gt;Fix widgets hovering in library UI when DPI is not 100&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1108 &lt;a href="https://github.com/Igalia/wolvic/pull/1108"&gt;Increase logical size and resolution of Web pages (relanded)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #1111 &lt;a href="https://github.com/Igalia/wolvic/pull/1111"&gt;Add head lock feature in hamburger menu&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #1113 &lt;a href="https://github.com/Igalia/wolvic/pull/1113"&gt;Also trigger key event when we scroll by D-pad&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1114 &lt;a href="https://github.com/Igalia/wolvic/pull/1114"&gt;Fix selection menu location for web pages&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1116 &lt;a href="https://github.com/Igalia/wolvic/pull/1116"&gt;Desktop Mode overrides for popular Chinese websites&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1119 &lt;a href="https://github.com/Igalia/wolvic/pull/1119"&gt;Hide brightness button when playing video in Passthrough&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1124 &lt;a href="https://github.com/Igalia/wolvic/pull/1124"&gt;Support head lock&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1085 &lt;a href="https://github.com/Igalia/wolvic/pull/1085"&gt;Auto Enter WebXR&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1126 &lt;a href="https://github.com/Igalia/wolvic/pull/1126"&gt;Fix SnapdragonSpaces build docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1125 &lt;a href="https://github.com/Igalia/wolvic/pull/1125"&gt;Prevent windows out of reach&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1127 &lt;a href="https://github.com/Igalia/wolvic/pull/1127"&gt;Revert "Enable showing all build warning"&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1129 &lt;a href="https://github.com/Igalia/wolvic/pull/1129"&gt;Fix several issues related to "center windows vertically" and drag move in curved mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1130 &lt;a href="https://github.com/Igalia/wolvic/pull/1130"&gt;Add group for experimental features in display settings&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1131 &lt;a href="https://github.com/Igalia/wolvic/pull/1131"&gt;Download Keyboard dictionaries on demand&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1132 &lt;a href="https://github.com/Igalia/wolvic/pull/1132"&gt;Add dictionaries to download in props.json&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1136 &lt;a href="https://github.com/Igalia/wolvic/pull/1136"&gt;Different density and DPI per build&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1137 &lt;a href="https://github.com/Igalia/wolvic/pull/1137"&gt;Bump actions/setup-java from 3 to 4&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1135 &lt;a href="https://github.com/Igalia/wolvic/pull/1135"&gt;Add two new environments for 1.5.2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1140 &lt;a href="https://github.com/Igalia/wolvic/pull/1140"&gt;Fix disk LRU cache key formatting error&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1142 &lt;a href="https://github.com/Igalia/wolvic/pull/1142"&gt;[ML2] Disable Hardware Acceleration for rendering UI widgets&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1143 &lt;a href="https://github.com/Igalia/wolvic/pull/1143"&gt;Rename environment to "Winter Night"&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1139 &lt;a href="https://github.com/Igalia/wolvic/pull/1139"&gt;[ML2] Add 3D controller model&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1146 &lt;a href="https://github.com/Igalia/wolvic/pull/1146"&gt;Set default density to 1.25&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(opened) #1147 &lt;a href="https://github.com/Igalia/wolvic/pull/1147"&gt;Do not let headlock update the position of the window while resizing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(opened) #1148 &lt;a href="https://github.com/Igalia/wolvic/pull/1148"&gt;Press on the skybox to reorient&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1152 &lt;a href="https://github.com/Igalia/wolvic/pull/1152"&gt;Initialize the VR external context after initializing Java&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1163 &lt;a href="https://github.com/Igalia/wolvic/pull/1163"&gt;Extract launch parameter names to constants&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1165 &lt;a href="https://github.com/Igalia/wolvic/pull/1165"&gt;Lower the maximum display DPI to 300&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1169 &lt;a href="https://github.com/Igalia/wolvic/pull/1169"&gt;Fix bug when moving large windows&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1170 &lt;a href="https://github.com/Igalia/wolvic/pull/1170"&gt;[Pico] Rename PicoXR device type to Pico4x&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1171 &lt;a href="https://github.com/Igalia/wolvic/pull/1171"&gt;Open immersive experiences directly&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1174 &lt;a href="https://github.com/Igalia/wolvic/pull/1174"&gt;Add UA override for courses.certify-ed.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1175 &lt;a href="https://github.com/Igalia/wolvic/pull/1175"&gt;Environments manager code logic cleanup&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1176 &lt;a href="https://github.com/Igalia/wolvic/pull/1176"&gt;Bump com.android.tools:r8 from 8.2.33 to 8.2.42&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1178 &lt;a href="https://github.com/Igalia/wolvic/pull/1178"&gt;Clean composing text when resetting the keyboard layout&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1185 &lt;a href="https://github.com/Igalia/wolvic/pull/1185"&gt;Allow disabling Latin Keyboard input auto complete&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1189 &lt;a href="https://github.com/Igalia/wolvic/pull/1189"&gt;Fix issues related to auto complete&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #1192 &lt;a href="https://github.com/Igalia/wolvic/pull/1192"&gt;Fix controllers disappear during video playback&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(opened) #1193 &lt;a href="https://github.com/Igalia/wolvic/pull/1193"&gt;Reset windows position when user tries to reorient via controllers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1194 &lt;a href="https://github.com/Igalia/wolvic/pull/1194"&gt;Improving compose text input&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1195 &lt;a href="https://github.com/Igalia/wolvic/pull/1195"&gt;Properly support vertical videos&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1197 &lt;a href="https://github.com/Igalia/wolvic/pull/1197"&gt;Fix controllers disappearing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1198 &lt;a href="https://github.com/Igalia/wolvic/pull/1198"&gt;Cleanup fullscreen code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1200 &lt;a href="https://github.com/Igalia/wolvic/pull/1200"&gt;Fix several issues when playing VR videos&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1182 &lt;a href="https://github.com/Igalia/wolvic/pull/1182"&gt;Add support for Pico Neo3 controllers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1205 &lt;a href="https://github.com/Igalia/wolvic/pull/1205"&gt;Fix typing in Android widgets without auto compose&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(opened) #1207 &lt;a href="https://github.com/Igalia/wolvic/pull/1207"&gt;Remove reliance of onFirstContentfulPaint&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1208 &lt;a href="https://github.com/Igalia/wolvic/pull/1208"&gt;Bump gradle/gradle-build-action from 2 to 3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1209 &lt;a href="https://github.com/Igalia/wolvic/pull/1209"&gt;Bump androidx.fragment:fragment from 1.4.1 to 1.6.2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) #1210 &lt;a href="https://github.com/Igalia/wolvic/pull/1210"&gt;Use doApply for setHeadLock and setWindowMovement&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1214 &lt;a href="https://github.com/Igalia/wolvic/pull/1214"&gt;Don't go back with buttons B and Y&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1217 &lt;a href="https://github.com/Igalia/wolvic/pull/1217"&gt;Synthesize FCP for cached pages&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1218 &lt;a href="https://github.com/Igalia/wolvic/pull/1218"&gt;Update telemetry-related privacy options&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1219 &lt;a href="https://github.com/Igalia/wolvic/pull/1219"&gt;[ML2] Add MagicLeap2 device type to VRControllerType&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #1220 &lt;a href="https://github.com/Igalia/wolvic/pull/1220"&gt;Update telemetry-related privacy options string translation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) #1223 &lt;a href="https://github.com/Igalia/wolvic/pull/1223"&gt;Modernize deprecated getMetrics(DisplayMetrics) in Display&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Issues opened/helped with
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;(opened) #797 &lt;a href="https://github.com/Igalia/wolvic/issues/797"&gt;Modernize deprecated updateConfiguration(Configuration,DisplayMetrics) in Resources&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(opened) #798 &lt;a href="https://github.com/Igalia/wolvic/issues/798"&gt;Use MediaStore.Downloads to index downloads instead&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #799 &lt;a href="https://github.com/Igalia/wolvic/issues/799"&gt;Modernize deprecated getMetrics(DisplayMetrics) in Display&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #800 &lt;a href="https://github.com/Igalia/wolvic/issues/800"&gt;Modernize deprecated setSystemUiVisibility(int) and related flags in View&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #801 &lt;a href="https://github.com/Igalia/wolvic/issues/801"&gt;Modernize deprecated AsyncTask&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #802 &lt;a href="https://github.com/Igalia/wolvic/issues/802"&gt;Modernize deprecated getConnectionInfo() in WifiInfo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #803 &lt;a href="https://github.com/Igalia/wolvic/issues/803"&gt;Modernize deprecated CONNECTIVITY_ACTION in ConnectivityManager (and bug fix on new methods)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(opened) #805 &lt;a href="https://github.com/Igalia/wolvic/issues/805"&gt;Modernize deprecated JobIntentService&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #810 &lt;a href="https://github.com/Igalia/wolvic/issues/810"&gt;Remove deprecated cookieLifetime&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #822 &lt;a href="https://github.com/Igalia/wolvic/issues/822"&gt;Modernize deprecated dispatchConfigurationChanged(Configuration)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #823 &lt;a href="https://github.com/Igalia/wolvic/issues/823"&gt;Upgrade the CMakeList.txt&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #835 &lt;a href="https://github.com/Igalia/wolvic/issues/835"&gt;Missing some symbols / keys from the virtual keyboard &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #841 &lt;a href="https://github.com/Igalia/wolvic/issues/841"&gt;Migrate from org.mozilla.components:browser-search to feature-search&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #214 &lt;a href="https://github.com/Igalia/wolvic/issues/214"&gt;Firefox Accounts authentication breaks if you navigate to another page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #845 &lt;a href="https://github.com/Igalia/wolvic/issues/845"&gt;Keyboard layout doesn't match the system's language &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #777 &lt;a href="https://github.com/Igalia/wolvic/issues/777"&gt;Need to format file sizes consistently&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #653 &lt;a href="https://github.com/Igalia/wolvic/issues/653"&gt;Use a different application name for HVR mainland China package&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #89 &lt;a href="https://github.com/Igalia/wolvic/issues/89"&gt;[OpenXR] When headset tracking is off, windows appear at "ground" level (Oculus)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #778 &lt;a href="https://github.com/Igalia/wolvic/issues/778"&gt;The Download Confirmation Dialog shouldn't center the question&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #423 &lt;a href="https://github.com/Igalia/wolvic/issues/423"&gt;Implement date/time picker&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #654 &lt;a href="https://github.com/Igalia/wolvic/issues/654"&gt;Target Android API level 32&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #688 &lt;a href="https://github.com/Igalia/wolvic/issues/688"&gt;Keep the selected options of HTML &amp;lt;select&amp;gt; multiple Attribute &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #875 &lt;a href="https://github.com/Igalia/wolvic/issues/875"&gt;Dark mode support &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #715 &lt;a href="https://github.com/Igalia/wolvic/issues/715"&gt;Remove WaveVR build dependency&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #890 &lt;a href="https://github.com/Igalia/wolvic/issues/890"&gt;Local Gecko builds are not used by default when building a package&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #896 &lt;a href="https://github.com/Igalia/wolvic/issues/896"&gt;DateTime picker prompt dialog is not properly triggered&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #922 &lt;a href="https://github.com/Igalia/wolvic/issues/922"&gt;Add Yandex to the list of available search engines &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(closed) #928 &lt;a href="https://github.com/Igalia/wolvic/issues/928"&gt;Missing the "Share with other apps" option in the downloads lists&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #923 &lt;a href="https://github.com/Igalia/wolvic/issues/923"&gt;Youtube VR videos with lower quality than expected &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #929 &lt;a href="https://github.com/Igalia/wolvic/issues/929"&gt;Search in page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #943 &lt;a href="https://github.com/Igalia/wolvic/issues/943"&gt;The 'Address bar auto-complete' feature can not be disabled &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #939 &lt;a href="https://github.com/Igalia/wolvic/issues/939"&gt;Tabs get closed with updates&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #949 &lt;a href="https://github.com/Igalia/wolvic/issues/949"&gt;"RESTART NOW" does not restart&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #940 &lt;a href="https://github.com/Igalia/wolvic/issues/940"&gt;Implement the feedback form with a native UI dialog &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #717 &lt;a href="https://github.com/Igalia/wolvic/issues/717"&gt;Youtube Captions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #964 &lt;a href="https://github.com/Igalia/wolvic/issues/964"&gt;False positive network status when starting Wolvic&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #874 &lt;a href="https://github.com/Igalia/wolvic/issues/874"&gt;No playback in Apple TV streaming service &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #712 &lt;a href="https://github.com/Igalia/wolvic/issues/712"&gt;Too much restart needed to restablish unstable connection&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #666 &lt;a href="https://github.com/Igalia/wolvic/issues/666"&gt;Persistent setting for the passthrough mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #493 &lt;a href="https://github.com/Igalia/wolvic/issues/493"&gt;Increase window parameter adjustment options in resize menu&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #353 &lt;a href="https://github.com/Igalia/wolvic/issues/353"&gt;Download dialog cannot show repeatedly&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #482 &lt;a href="https://github.com/Igalia/wolvic/issues/482"&gt;Empty canvas element after exiting VR&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #662 &lt;a href="https://github.com/Igalia/wolvic/issues/662"&gt; Leak of surface when exiting VR mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #545 &lt;a href="https://github.com/Igalia/wolvic/issues/545"&gt;3D SBS not working in curved mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #489 &lt;a href="https://github.com/Igalia/wolvic/issues/489"&gt;[Privacy and Security] Add trusted Root CA option&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #461 &lt;a href="https://github.com/Igalia/wolvic/issues/461"&gt;Add more options to view 3D-SBS-Videos&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #927 &lt;a href="https://github.com/Igalia/wolvic/issues/927"&gt;Drag and rotate windows using the controller&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #619 &lt;a href="https://github.com/Igalia/wolvic/issues/619"&gt;When running a noapi build, a black screen is displayed&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #970 &lt;a href="https://github.com/Igalia/wolvic/issues/970"&gt;Some Web XR Links do not work in Kiosk Mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #977 &lt;a href="https://github.com/Igalia/wolvic/issues/977"&gt;Restore the FxR inherited versionCode auto generation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #981 &lt;a href="https://github.com/Igalia/wolvic/issues/981"&gt;Opening a URL from the command line always opens a new tab&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #976 &lt;a href="https://github.com/Igalia/wolvic/issues/976"&gt;[OpenXR] Revamp finalization of OpenXRLayer subclasses&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #998 &lt;a href="https://github.com/Igalia/wolvic/issues/998"&gt;Date picker can be too tall&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #86 &lt;a href="https://github.com/Igalia/wolvic/issues/86"&gt;Rendering artifacts in Atomic City scene of Mozilla Hubs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #225 &lt;a href="https://github.com/Igalia/wolvic/issues/225"&gt;No audio casting stream from Wolvic&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #226 &lt;a href="https://github.com/Igalia/wolvic/issues/226"&gt;No sound effects playing Moon Rider (https://moonrider.xyz)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #782 &lt;a href="https://github.com/Igalia/wolvic/issues/782"&gt;Support KTX v2 &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #660 &lt;a href="https://github.com/Igalia/wolvic/issues/660"&gt;Speech input on vr keyboard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #171 &lt;a href="https://github.com/Igalia/wolvic/issues/171"&gt;Fragmented subtitles in 3D side-by-side movie&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #498 &lt;a href="https://github.com/Igalia/wolvic/issues/498"&gt;Needs to start in desktop mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #299 &lt;a href="https://github.com/Igalia/wolvic/issues/299"&gt;in kiosk mode, maybe it needs a loading progress bar of the webxr content&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #87 &lt;a href="https://github.com/Igalia/wolvic/issues/87"&gt;Saving and loading don't work in Brushworkvr app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #1011 &lt;a href="https://github.com/Igalia/wolvic/issues/1011"&gt;Dot (.) unconditionally appended to voice search text&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1013 &lt;a href="https://github.com/Igalia/wolvic/issues/1013"&gt;Voice input content UI overflow and not stick to the latest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #963 &lt;a href="https://github.com/Igalia/wolvic/issues/963"&gt;Environments download should use &lt;code&gt;getFilesDir()&lt;/code&gt;/&lt;code&gt;getCacheDir()&lt;/code&gt; to store the downloaded zip file&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #598 &lt;a href="https://github.com/Igalia/wolvic/issues/598"&gt;Media stream detached from window in some cases?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #731 &lt;a href="https://github.com/Igalia/wolvic/issues/731"&gt;💡 The 360° background could be updated according the webpage &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #345 &lt;a href="https://github.com/Igalia/wolvic/issues/345"&gt;on a shared device clearing cache and history it does not reset everything &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #236 &lt;a href="https://github.com/Igalia/wolvic/issues/236"&gt;softlocking quest when opening dll file in external app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1023 &lt;a href="https://github.com/Igalia/wolvic/issues/1023"&gt;Evaluate the need for the media session extension&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #473 &lt;a href="https://github.com/Igalia/wolvic/issues/473"&gt;Add a glTF/glb loader&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #1029 &lt;a href="https://github.com/Igalia/wolvic/issues/1029"&gt;Make the CrashReporterService work again&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1044 &lt;a href="https://github.com/Igalia/wolvic/issues/1044"&gt;Implement an Android's MediaPlayer AudioEngine&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #99 &lt;a href="https://github.com/Igalia/wolvic/issues/99"&gt;Click and Drag windows&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1055 &lt;a href="https://github.com/Igalia/wolvic/issues/1055"&gt;There is no curved window in full-screen video mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1058 &lt;a href="https://github.com/Igalia/wolvic/issues/1058"&gt;华为vr glass&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1059 &lt;a href="https://github.com/Igalia/wolvic/issues/1059"&gt;华为vrglass&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1062 &lt;a href="https://github.com/Igalia/wolvic/issues/1062"&gt;Not installable on Quest 3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1067 &lt;a href="https://github.com/Igalia/wolvic/issues/1067"&gt;Enable haptic feedback when controller pointer swipes across widgets/web page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1069 &lt;a href="https://github.com/Igalia/wolvic/issues/1069"&gt;Allow 'Device Name' change in Firefox/Mozzila Sync settings.&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #1065 &lt;a href="https://github.com/Igalia/wolvic/issues/1065"&gt;can wolvic support WebGPU? and if not, what's the roadmap?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #737 &lt;a href="https://github.com/Igalia/wolvic/issues/737"&gt;Request: autocorrect/text prediction&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1078 &lt;a href="https://github.com/Igalia/wolvic/issues/1078"&gt;How to improve sharpness at 0.5 window size&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1093 &lt;a href="https://github.com/Igalia/wolvic/issues/1093"&gt;Allow users to use the Zoom to change the size of the rendered web content&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #1097 &lt;a href="https://github.com/Igalia/wolvic/issues/1097"&gt;CORS errors on same origin inconsistent with other browsers (Same Origin Policy)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #544 &lt;a href="https://github.com/Igalia/wolvic/issues/544"&gt;InputMethodManager: Display ID mismatch found&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1088 &lt;a href="https://github.com/Igalia/wolvic/issues/1088"&gt;Default values for display density and DPI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #1110 &lt;a href="https://github.com/Igalia/wolvic/issues/1110"&gt;Spatial navigation support for AR/VR controllers with D-pads&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(opened) #1121 &lt;a href="https://github.com/Igalia/wolvic/issues/1121"&gt;Investigate the feasibility of newer Mozilla Android components for sessions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1128 &lt;a href="https://github.com/Igalia/wolvic/issues/1128"&gt;Download keyboard auto-complete dictionaries on demand&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #938 &lt;a href="https://github.com/Igalia/wolvic/issues/938"&gt;Zoom in and out&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1133 &lt;a href="https://github.com/Igalia/wolvic/issues/1133"&gt;Pico 4 upload a new environment?(adb command not recognize wolvic * file/folder) &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1134 &lt;a href="https://github.com/Igalia/wolvic/issues/1134"&gt;Request to adjust screen distance and increase resolution for pico4&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1164 &lt;a href="https://github.com/Igalia/wolvic/issues/1164"&gt;Setting DPI too high causes thermal runaway&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1166 &lt;a href="https://github.com/Igalia/wolvic/issues/1166"&gt;Disabling 360 background&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1162 &lt;a href="https://github.com/Igalia/wolvic/issues/1162"&gt;wolvic support to play 360 view &amp;amp; Horizontal Panoramic View pictures which is photoed by the customers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #1183 &lt;a href="https://github.com/Igalia/wolvic/issues/1183"&gt;Text added to the wrong place when autocomplete is active&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1181 &lt;a href="https://github.com/Igalia/wolvic/issues/1181"&gt;Controllers disappear during video playback&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1186 &lt;a href="https://github.com/Igalia/wolvic/issues/1186"&gt;Autocomplete: blank space requires tapping on the spacebar twice&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) #1187 &lt;a href="https://github.com/Igalia/wolvic/issues/1187"&gt;Autocomplete: keyboard becomes sluggish when autocompleting medium-long words&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(addressed) #1211 &lt;a href="https://github.com/Igalia/wolvic/issues/1211"&gt;Automatic VR 360 WebXR Open&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>browser</category>
      <category>opensource</category>
      <category>vr</category>
      <category>xr</category>
    </item>
    <item>
      <title>Code reviews and Suggestions from SARIF report</title>
      <dc:creator>Hollow Man</dc:creator>
      <pubDate>Tue, 16 May 2023 19:31:38 +0000</pubDate>
      <link>https://dev.to/hollowman6/code-reviews-and-suggestions-from-sarif-report-1271</link>
      <guid>https://dev.to/hollowman6/code-reviews-and-suggestions-from-sarif-report-1271</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;SARIF support for Reviewdog&lt;/p&gt;

&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;p&gt;Maintainer Must-Haves&lt;/p&gt;

&lt;h3&gt;
  
  
  App Link
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/HollowMan6/sarif4reviewdog/pull/5"&gt;https://github.com/HollowMan6/sarif4reviewdog/pull/5&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tVHfS24e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/srz6zwz5yv28v8w7sgd5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tVHfS24e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/srz6zwz5yv28v8w7sgd5.png" alt="eg" width="800" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;SARIF, the Static Analysis Results Interchange Format, is a standard, JSON-based format for the output of static analysis tools.&lt;/p&gt;

&lt;p&gt;This action enables the maintainers to integrate the fixes proposed by static code analysis tools right from the PR comments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Source Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/HollowMan6/sarif4reviewdog"&gt;https://github.com/HollowMan6/sarif4reviewdog&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissive License
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://choosealicense.com/licenses/mit/"&gt;MIT&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/orgs/community/discussions/52156"&gt;https://github.com/orgs/community/discussions/52156&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub Code Scanning supports generating alerts from the SARIF report, but it can't show the proposed fixes from the report. It can be a good addition to give us the option to make commits to the codebase based on the proposed fixes.&lt;/p&gt;

&lt;p&gt;Then I submitted the feature request, but no one respond anything, so why not realize it by myself instead?&lt;/p&gt;

&lt;h3&gt;
  
  
  How I built it
&lt;/h3&gt;

&lt;p&gt;In SARIF, The &lt;a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317881"&gt;fix object&lt;/a&gt; represents a proposed fix for the problem indicated by the Result. It specifies a set of artifacts to modify. For each artifact, it specifies regions to remove and provides new content to insert.&lt;/p&gt;

&lt;p&gt;I build a general converter from SARIF to &lt;a href="https://github.com/reviewdog/reviewdog/tree/master/proto/rdf"&gt;Reviewdog Diagnostic Format (RDFormat)&lt;/a&gt;, then use Reviewdog to give suggested code changes as well as the context of the changes for PR reviewing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources/Info
&lt;/h3&gt;

&lt;p&gt;This Action is currently used by &lt;a href="https://github.com/kubescape/github-action#automatically-suggest-fixes"&gt;kubescape&lt;/a&gt;, a Cloud Native Computing Foundation (CNCF) sandbox project. It is an open-source Kubernetes security platform and includes risk analysis, security compliance, and misconfiguration scanning. Targeted at the DevSecOps practitioner or platform engineer, it offers an easy-to-use CLI interface, flexible output formats, and automated scanning capabilities.&lt;/p&gt;

</description>
      <category>githubhack23</category>
      <category>opensource</category>
      <category>github</category>
      <category>devops</category>
    </item>
    <item>
      <title>My CNCF LFX Mentorship Spring 2023 Project at Kubescape</title>
      <dc:creator>Hollow Man</dc:creator>
      <pubDate>Sun, 14 May 2023 12:49:20 +0000</pubDate>
      <link>https://dev.to/hollowman6/my-cncf-lfx-mentorship-spring-2023-project-at-kubescape-47nd</link>
      <guid>https://dev.to/hollowman6/my-cncf-lfx-mentorship-spring-2023-project-at-kubescape-47nd</guid>
      <description>&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=ZBK5wKpvM3s&amp;amp;t=1773s" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=ZBK5wKpvM3s&amp;amp;t=1773s&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Project Link: &lt;a href="https://mentorship.lfx.linuxfoundation.org/project/138e9cac-ec86-43cb-a04f-c2980e3c2865" rel="noopener noreferrer"&gt;CNCF - Kubescape: Release engineering: add Kubescape to commonly-requested package managers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://landscape.cncf.io/card-mode?project=sandbox&amp;amp;selected=kubescape" rel="noopener noreferrer"&gt;kubescape&lt;/a&gt; is a Cloud Native Computing Foundation (CNCF) sandbox project. It is an open-source Kubernetes security platform and includes risk analysis, security compliance, and misconfiguration scanning. Targeted at the DevSecOps practitioner or platform engineer, it offers an easy-to-use CLI interface, flexible output formats, and automated scanning capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  List of things I have done
&lt;/h2&gt;

&lt;p&gt;Documentations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kubescape/kubescape/wiki/Publishing" rel="noopener noreferrer"&gt;Publishing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repo and Packages created:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kubescape/packaging" rel="noopener noreferrer"&gt;kubescape/packaging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://build.opensuse.org/package/show/home:kubescape/kubescape" rel="noopener noreferrer"&gt;OpenSUSE Open Build Service home:kubescape/kubescape&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://launchpad.net/~kubescape/+archive/ubuntu/kubescape" rel="noopener noreferrer"&gt;Ubuntu Launchpad PPA kubescape/kubescape&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.chocolatey.org/packages/kubescape" rel="noopener noreferrer"&gt;Chocolatey kubescape&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://snapcraft.io/kubescape" rel="noopener noreferrer"&gt;Snapcraft Store kubescape&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aur.archlinux.org/packages/kubescape" rel="noopener noreferrer"&gt;Arch Linux AUR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/HollowMan6/sarif4reviewdog" rel="noopener noreferrer"&gt;SARIF for Reviewdog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PRs opened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(merged) kubescape/kubescape #1095 &lt;a href="https://github.com/kubescape/kubescape/pull/1095" rel="noopener noreferrer"&gt;fix(build): LICENSE file in release tarballs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1105 &lt;a href="https://github.com/kubescape/kubescape/pull/1105" rel="noopener noreferrer"&gt;fix(README): broken links&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1140 &lt;a href="https://github.com/kubescape/kubescape/pull/1140" rel="noopener noreferrer"&gt;ci(release): fix publishing krew plugin; add '.exe' extension to Windows binary&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1147 &lt;a href="https://github.com/kubescape/kubescape/pull/1147" rel="noopener noreferrer"&gt;Change installation path to ~/.kubescape/bin&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1148 &lt;a href="https://github.com/kubescape/kubescape/pull/1148" rel="noopener noreferrer"&gt;arm64 release binaries for CI and Krew&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1169 &lt;a href="https://github.com/kubescape/kubescape/pull/1169" rel="noopener noreferrer"&gt;Add kubescape.exe to the release assets&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1184 &lt;a href="https://github.com/kubescape/kubescape/pull/1184" rel="noopener noreferrer"&gt;feat(sarif): add fix object in generated reports&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1185 &lt;a href="https://github.com/kubescape/kubescape/pull/1185" rel="noopener noreferrer"&gt;fix(fix): mixed up change summary list&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1186 &lt;a href="https://github.com/kubescape/kubescape/pull/1186" rel="noopener noreferrer"&gt;Invoke packaging workflow to update after release&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1196 &lt;a href="https://github.com/kubescape/kubescape/pull/1196" rel="noopener noreferrer"&gt;Move building instructions to wiki, add more installation instructions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1199 &lt;a href="https://github.com/kubescape/kubescape/pull/1199" rel="noopener noreferrer"&gt;Update installation script&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1210 &lt;a href="https://github.com/kubescape/kubescape/pull/1210" rel="noopener noreferrer"&gt;ci: update before install packages&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1213 &lt;a href="https://github.com/kubescape/kubescape/pull/1213" rel="noopener noreferrer"&gt;Deprecate kubescape-windows-latest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1214 &lt;a href="https://github.com/kubescape/kubescape/pull/1214" rel="noopener noreferrer"&gt;Add ref to workflow dispatch&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1216 &lt;a href="https://github.com/kubescape/kubescape/pull/1216" rel="noopener noreferrer"&gt;Make powershell Windows installation user path available immediately&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1236 &lt;a href="https://github.com/kubescape/kubescape/pull/1236" rel="noopener noreferrer"&gt;Deprecate kubescape-windows-latest and fix CI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/kubescape #1238 &lt;a href="https://github.com/kubescape/kubescape/pull/1238" rel="noopener noreferrer"&gt;Fix downloading arm64 binary for kubescape&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/github-action #32 &lt;a href="https://github.com/kubescape/github-action/pull/32" rel="noopener noreferrer"&gt;Support for code reviews instead with PRs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/github-action #34 &lt;a href="https://github.com/kubescape/github-action/pull/34" rel="noopener noreferrer"&gt;Fix start new PR with own repo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/github-action #37 &lt;a href="https://github.com/kubescape/github-action/pull/37" rel="noopener noreferrer"&gt;Add exceptions parameters back&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/github-action #38 &lt;a href="https://github.com/kubescape/github-action/pull/38" rel="noopener noreferrer"&gt;Keep kubescape github-action workflow up to date&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/github-action #41 &lt;a href="https://github.com/kubescape/github-action/pull/41" rel="noopener noreferrer"&gt;Intergrate fix with comments&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/github-action #42 &lt;a href="https://github.com/kubescape/github-action/pull/42" rel="noopener noreferrer"&gt;Version bumps start PRs instead of committing directly&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/github-action #43 &lt;a href="https://github.com/kubescape/github-action/pull/43" rel="noopener noreferrer"&gt;Split the suggest fix workflow and update docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/vscode-kubescape #11 &lt;a href="https://github.com/kubescape/vscode-kubescape/pull/11" rel="noopener noreferrer"&gt;Remove platformPackages config&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/vscode-kubescape #12 &lt;a href="https://github.com/kubescape/vscode-kubescape/pull/12" rel="noopener noreferrer"&gt;Bump kubescape version into v2.3.1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/lens-extension #16 &lt;a href="https://github.com/kubescape/lens-extension/pull/16" rel="noopener noreferrer"&gt;Bump kubescape version into v2.3.1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/node-kubescape #3 &lt;a href="https://github.com/kubescape/node-kubescape/pull/3" rel="noopener noreferrer"&gt;Support for ARM64 binaries as well as kubescape.exe&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) kubescape/homebrew-tap #7 &lt;a href="https://github.com/kubescape/homebrew-tap/pull/7" rel="noopener noreferrer"&gt;Add Auto Release CI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(rejected) kubernetes-sigs/controller-runtime #2266 &lt;a href="https://github.com/kubernetes-sigs/controller-runtime/pull/2266" rel="noopener noreferrer"&gt;🐛 Support get config inside snap with SNAP_REAL_HOME&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(rejected) kubernetes/kubernetes #117165 &lt;a href="https://github.com/kubernetes/kubernetes/pull/117165" rel="noopener noreferrer"&gt;client-go: support detect homedir with SNAP_REAL_HOME and os/user.HomeDir&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) ScoopInstaller/Main #4757 &lt;a href="https://github.com/ScoopInstaller/Main/pull/4757" rel="noopener noreferrer"&gt;kubescape: Update url and binary naming&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(pending) gentoo/gentoo #30595 &lt;a href="https://github.com/gentoo/gentoo/pull/30595" rel="noopener noreferrer"&gt;sys-cluster/kubescape: new package, add 2.3.3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(merged) chocolatey-community/chocolatey-packages #2226 &lt;a href="https://github.com/chocolatey-community/chocolatey-packages/pull/2226" rel="noopener noreferrer"&gt;(kubescape) Add Kubescape package&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Issues opened/helped with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(resolved) kubescape/kubescape #195 &lt;a href="https://github.com/kubescape/kubescape/issues/195" rel="noopener noreferrer"&gt;Provide ARM64 release binaries&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) kubescape/kubescape #400 &lt;a href="https://github.com/kubescape/kubescape/issues/400" rel="noopener noreferrer"&gt;Add Kubescape to packages management for easier installation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) kubescape/kubescape #720 &lt;a href="https://github.com/kubescape/kubescape/pull/720" rel="noopener noreferrer"&gt;Error Fixed when downloading on azure cloud vm environment&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) kubescape/kubescape #1014 &lt;a href="https://github.com/kubescape/kubescape/issues/1014" rel="noopener noreferrer"&gt;Package manager support: homebrew&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) kubescape/kubescape #1015 &lt;a href="https://github.com/kubescape/kubescape/issues/1015" rel="noopener noreferrer"&gt;kubescape installed in first directory in $PATH under $HOME&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(helped) kubescape/kubescape #1033 &lt;a href="https://github.com/kubescape/kubescape/issues/1033" rel="noopener noreferrer"&gt;Generate SLSA provenance for builds&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) kubescape/kubescape #1112 &lt;a href="https://github.com/kubescape/kubescape/issues/1112" rel="noopener noreferrer"&gt;can't install Kubescape with krew on Apple Silicon Mac&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) kubescape/kubescape #1142 &lt;a href="https://github.com/kubescape/kubescape/issues/1142" rel="noopener noreferrer"&gt;Package manager support: RPM&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) kubescape/kubescape #1143 &lt;a href="https://github.com/kubescape/kubescape/issues/1143" rel="noopener noreferrer"&gt;Package manager support: deb&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) kubescape/kubescape #1168 &lt;a href="https://github.com/kubescape/kubescape/issues/1168" rel="noopener noreferrer"&gt;Add kubescape.exe to the release assets to replace kubescape-windows-latest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) kubescape/kubescape #1183 &lt;a href="https://github.com/kubescape/kubescape/issues/1183" rel="noopener noreferrer"&gt;Add fix object in Kubescape generated SARIF reports when available&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) kubescape/kubescape #1215 &lt;a href="https://github.com/kubescape/kubescape/pull/1215" rel="noopener noreferrer"&gt;Fix issue 11552&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(helped) kubescape/kubescape #1237 &lt;a href="https://github.com/kubescape/kubescape/issues/1237" rel="noopener noreferrer"&gt;Download and Installing Wrong Binary For Apple M1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(reviewed) kubescape/kubescape #1239 &lt;a href="https://github.com/kubescape/kubescape/pull/1239" rel="noopener noreferrer"&gt;Added instructions to setup kubescape locally&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) kubescape/k8s-interface #46 &lt;a href="https://github.com/kubescape/k8s-interface/issues/46" rel="noopener noreferrer"&gt;Kubescape supports getting packed as a snap app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) kubescape/k8s-interface #46 &lt;a href="https://github.com/kubescape/k8s-interface/issues/46" rel="noopener noreferrer"&gt;Kubescape supports getting packed as a snap app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(pending response) github/community #52156 &lt;a href="https://github.com/orgs/community/discussions/52156" rel="noopener noreferrer"&gt;Support code auto-fixes for GitHub Code Scanning&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) chocolatey-community #2186 &lt;a href="https://github.com/orgs/chocolatey-community/discussions/2186" rel="noopener noreferrer"&gt;Migrate kubescape package&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) chocolatey-community/chocolatey-packages #2190 &lt;a href="https://github.com/chocolatey-community/chocolatey-packages/issues/2190" rel="noopener noreferrer"&gt;(kubescape) Migrate package&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(resolved) snapcraft/store-requests #34661 &lt;a href="https://forum.snapcraft.io/t/request-for-classic-confinement-and-name-change-for-cli-kubescape/34661" rel="noopener noreferrer"&gt;Request for classic confinement and name change for cli-kubescape&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(pending response) snapcraft/snapd #34683 &lt;a href="https://forum.snapcraft.io/t/feature-request-stop-using-snap-real-home-to-visit-real-home-files/34683" rel="noopener noreferrer"&gt;Feature Request: Stop using $SNAP_REAL_HOME to visit real home files&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project summaries
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Packaging
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://build.opensuse.org/package/show/home:kubescape/kubescape" rel="noopener noreferrer"&gt;OpenSUSE Build Service (DEB and RPM)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubescape/packaging/blob/main/kubescape.spec" rel="noopener noreferrer"&gt;RPM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubescape/packaging/tree/main/deb/debian" rel="noopener noreferrer"&gt;Ubuntu Launchpad PPA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubescape/homebrew-tap" rel="noopener noreferrer"&gt;Homebrew Tap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/HollowMan6/chocolatey-packages/tree/master/automatic/kubescape" rel="noopener noreferrer"&gt;Chocolatey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubescape/packaging/blob/main/snap/snapcraft.yaml" rel="noopener noreferrer"&gt;Snapcraft&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubescape/packaging/blob/main/PKGBUILD" rel="noopener noreferrer"&gt;AUR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/HollowMan6/gentoo/tree/kubescape/sys-cluster/kubescape" rel="noopener noreferrer"&gt;Gentoo Portage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other packages managers that have already been available and not introduced by me during this project period:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://build.opensuse.org/package/show/devel:kubic/kubescape" rel="noopener noreferrer"&gt;OpenSUSE Zypper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://formulae.brew.sh/formula/kubescape#default" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kubernetes-sigs/krew-index/pull/3106" rel="noopener noreferrer"&gt;Krew&lt;/a&gt; (I added the ARM64 support for Krew)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/security/kubescape/default.nix" rel="noopener noreferrer"&gt;Nix-pkgs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://scoop.sh/#/apps?q=kubescape&amp;amp;s=0&amp;amp;d=1&amp;amp;o=true&amp;amp;id=1f5ae05eaafe3e7a26505f0889101e0da91ffe91" rel="noopener noreferrer"&gt;Scoop&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  GitHub Actions Release CI
&lt;/h3&gt;

&lt;p&gt;I helped improve the Kubescape GitHub Actions release CI process, where I added the ARM64 build and tested for the GitHub Actions release CI workflow. I use QEMU with Docker to simulate the Linux ARM64 environment for building and testing the binaries. For macOS M1/M2, I investigated how to cross-build libgit2 C code and use Golang cross-compilation to build the binaries.&lt;/p&gt;

&lt;p&gt;I also helped add the auto version bumping CI for &lt;a href="https://github.com/kubescape/homebrew-tap/blob/main/.github/workflows/release.yml" rel="noopener noreferrer"&gt;kubescape/homebrew-tap&lt;/a&gt;, &lt;a href="https://github.com/kubescape/packaging/blob/main/.github/workflows/release.yml" rel="noopener noreferrer"&gt;kubescape/packaging&lt;/a&gt;, and &lt;a href="https://github.com/kubescape/github-action/blob/main/.github/workflows/release.yaml" rel="noopener noreferrer"&gt;kubescape/github-action&lt;/a&gt;. After the release is made, we trigger these CIs so that the kubescape versions in these repositories can get upgraded automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Actions Code Review
&lt;/h3&gt;

&lt;p&gt;I helped improve the Kubescape GitHub Actions fix suggestions code review process, where I created the workflow which works by collecting the &lt;a href="https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=sarif" rel="noopener noreferrer"&gt;SARIF (Static Analysis Results Interchange Format)&lt;/a&gt; file that kubescape generates. Then, with the help of &lt;a href="https://github.com/marketplace/actions/sarif-support-for-reviewdog" rel="noopener noreferrer"&gt;HollowMan6/sarif4reviewdog&lt;/a&gt;, convert the SARIF file into &lt;a href="https://github.com/reviewdog/reviewdog/tree/master/proto/rdf" rel="noopener noreferrer"&gt;RDFormat (Reviewdog Diagnostic Format)&lt;/a&gt; and generate reviews for code fix suggestions on GitHub Actions using &lt;a href="https://github.com/reviewdog/reviewdog" rel="noopener noreferrer"&gt;Reviewdog&lt;/a&gt;. I also helped add the “fix" object support for the Kubescape-generated SARIF report.&lt;/p&gt;

&lt;p&gt;In addition to the main project, I also helped the community with other issues like bug-fixing as well as feature-adding.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>cicd</category>
      <category>security</category>
    </item>
    <item>
      <title>Microsoft Reinforcement Learning Open Source Fest 2022 – Native CSV Parser</title>
      <dc:creator>Hollow Man</dc:creator>
      <pubDate>Sat, 13 Aug 2022 15:20:00 +0000</pubDate>
      <link>https://dev.to/hollowman6/microsoft-reinforcement-learning-open-source-fest-2022-native-csv-parser-fl</link>
      <guid>https://dev.to/hollowman6/microsoft-reinforcement-learning-open-source-fest-2022-native-csv-parser-fl</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y-UXoveS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hollowmansblog.files.wordpress.com/2022/08/rlosfest.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y-UXoveS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hollowmansblog.files.wordpress.com/2022/08/rlosfest.png" alt="" width="800" height="1274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=jnkxDdZF_gc&amp;amp;t=2276s"&gt;Reinforcement Learning (RL) Open Source Fest 2022 Final Project Presentations&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.microsoft.com/en-us/research/academic-program/rl-open-source-fest/alumni/#:~:text=Songlin"&gt;Shorter Introduction&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PR: &lt;a href="https://github.com/VowpalWabbit/vowpal_wabbit/pull/4073"&gt;https://github.com/VowpalWabbit/vowpal_wabbit/pull/4073&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tutorial: &lt;a href="https://vowpalwabbit.org/docs/vowpal_wabbit/python/latest/tutorials/cmd_csv_with_iris_dataset.html"&gt;https://vowpalwabbit.org/docs/vowpal_wabbit/python/latest/tutorials/cmd_csv_with_iris_dataset.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;My project here at the &lt;a href="https://www.microsoft.com/en-us/research/academic-program/rl-open-source-fest/"&gt;Reinforcement Learning Open Source Fest 2022&lt;/a&gt; is to add the &lt;a href="https://vowpalwabbit.org/rlos/2022/projects#native-csv-parsing"&gt;native CSV parsing&lt;/a&gt; feature for the &lt;a href="https://vowpalwabbit.org/"&gt;Vowpal Wabbit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So why do I choose to implement native CSV parsing? CSV is one of the most popular file formats used in the machine learning dataset and is often delivered as the default format in competitions such as Kaggle. CSV files have the same schema for each example, while VW text format doesn't. Although converters in Python and Perl have been written which convert these files to VW text format, it would be convenient if VW could understand CSV files natively. I also want to challenge myself, as there is a surprising amount of complexity in the design of implementing a generalized parser for CSV, so this project is as much about considering all of the design pieces as implementing a working parser. My choice and time devoted also pay off since my project has already got merged into the VW upstream !!!&lt;/p&gt;

&lt;h3&gt;
  
  
  About CSV
&lt;/h3&gt;

&lt;p&gt;CSV files are often separated by commas (&lt;code&gt;,&lt;/code&gt;) or tabs. however, alternative delimiter-separated files are often given a &lt;code&gt;.csv&lt;/code&gt; extension despite the use of a non-comma field separator. This loose terminology can cause problems in data exchange. Many applications that accept CSV files have options to select the delimiter character and the quotation character. Semicolons (&lt;code&gt;;&lt;/code&gt;) are often used instead of commas in many European locales in order to use the comma (&lt;code&gt;,&lt;/code&gt;) as the decimal separator and, possibly, the period (&lt;code&gt;.&lt;/code&gt;) as a decimal grouping character.&lt;/p&gt;

&lt;p&gt;Separating fields with the field separator is CSV's foundation, but commas in the data have to be handled specially.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do we handle CSV files?
&lt;/h3&gt;

&lt;p&gt;The short answer is that we follow the RFC 4180 and MIME standards.&lt;/p&gt;

&lt;p&gt;The 2005 technical standard RFC 4180 formalizes the CSV file format and defines the MIME type "text/csv" for the handling of text-based fields. However, the interpretation of the text of each field is still application-specific. Files that follow the RFC 4180 standard can simplify CSV exchange and should be widely portable. Here are its requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lines will end with CR or CRLF characters, and it is optional for the last line.&lt;/li&gt;
&lt;li&gt;CSV files can have an optional header record. There is no sure way to detect whether it is present, so care is required when importing.&lt;/li&gt;
&lt;li&gt;Each record should contain the same number of separated fields.&lt;/li&gt;
&lt;li&gt;Any field may be quoted with double quotes.&lt;/li&gt;
&lt;li&gt;Fields containing a double-quote or commas should be quoted.&lt;/li&gt;
&lt;li&gt;If double-quotes are used to enclose fields, then a double-quote in a field must be represented by two double-quote characters.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Dig into details
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Allows specifying the CSV field separator by --csv_separator, default is &lt;code&gt;,&lt;/code&gt;, but &lt;code&gt;"&lt;/code&gt; &lt;code&gt;|&lt;/code&gt; or &lt;code&gt;:&lt;/code&gt; are reserved and not allowed to use, since the double quote (&lt;code&gt;"&lt;/code&gt;) is for escape, vertical bar(&lt;code&gt;|&lt;/code&gt;) for separating the namespace and feature names, &lt;code&gt;:&lt;/code&gt; can be used in labels.&lt;/li&gt;
&lt;li&gt;For each separated field, auto remove the outer double-quotes of a cell when it pairs. &lt;code&gt;--csv_separator&lt;/code&gt; symbols that appeared inside the double-quoted cells are not considered as a separator but a normal string character.&lt;/li&gt;
&lt;li&gt;Double-quotes that appear at the start and end of the cell will be considered to enclose fields. Other quotes that appear elsewhere and out of the enclose fields will have no special meaning. (This is also how Microsoft Excel parses.)&lt;/li&gt;
&lt;li&gt;If double-quotes are used to enclose fields, then a double-quote appearing inside a field must be escaped by preceding it with another double quote, and will remove that escape symbol during parsing.&lt;/li&gt;
&lt;li&gt;Use header line for feature names (and possibly namespaces) / specify label and tag using &lt;code&gt;_label&lt;/code&gt; and &lt;code&gt;_tag&lt;/code&gt; by default. For each separated field in header except for tag and label, it may contain namespace and feature name separated by namespace separator, vertical bar(&lt;code&gt;|&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--csv_header&lt;/code&gt; to override the CSV header by providing the header. Combined with &lt;code&gt;--csv_no_file_header&lt;/code&gt;, we assume that there is no header in the CSV file and under such condition specifying &lt;code&gt;--csv_header&lt;/code&gt; for the header is a must.&lt;/li&gt;
&lt;li&gt;If the number of the separated fields for current parsing line is greater than the header, an error will be thrown.&lt;/li&gt;
&lt;li&gt;Trim the field for ASCII "white space"(&lt;code&gt;\r\n\f\v&lt;/code&gt;) as well as some UTF-8 BOM characters(&lt;code&gt;\xef\xbb\xbf&lt;/code&gt;) before separation.&lt;/li&gt;
&lt;li&gt; If no namespace is separated, will use empty namespace.&lt;/li&gt;
&lt;li&gt;Separator supports using &lt;code&gt;\t&lt;/code&gt; to represent tabs. Otherwise, if assigning more than one character, an error will be thrown.&lt;/li&gt;
&lt;li&gt;Directly read the label as string, interpret it using the VW text label parser.&lt;/li&gt;
&lt;li&gt;Will try to judge if the feature values are float or string, if NaN, will consider it as a string. quoted numbers are always considered as strings.&lt;/li&gt;
&lt;li&gt;If the feature value is empty, will skip that feature.&lt;/li&gt;
&lt;li&gt;Reset the parser when EOF of a file is met (for possible multiple input file support).&lt;/li&gt;
&lt;li&gt;Support using &lt;code&gt;--csv_ns_value&lt;/code&gt; to scale the namespace values by specifying the float ratio.
e.g. --csv_ns_value=a:0.5,b:0.3,:8, which the namespace a has a ratio of 0.5, b of 0.3, empty namespace of 8, other namespaces of 1.&lt;/li&gt;
&lt;li&gt;If all the cells in a line are empty, then consider it an empty line. CSV is not a good fit for the multiline format, as evidenced by many empty fields. The multiline format often means different lines have different schemas. However, I still leave the empty line support to ensure that it's flexible and extendable. In this case, users can still express multiline examples in CSV files, although it is not listed as supported. We still throw an error if the number of fields separated by the line doesn't match the previous, even if all the fields are empty, as this usually means typos that users may not intend.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Some statistics to share
&lt;/h2&gt;

&lt;p&gt;The project reaches 100% Test and Code Coverage. On my computer, it takes only 829 ms to handle 200000 examples, which is comparable to the equivalent VW custom format data file’s parsing speed of 623 ms, and is equivalent to 21.7 MB/s throughput.&lt;/p&gt;

&lt;p&gt;I have expected that little bit of slower between VW custom text format and the CSV format. The VW text parser can parse as it reads since generally the elements have a fixed position, while CSV parser needs to store the split elements into an array, and look up that array according to the header for labels, tags, namespace and feature values, also there's double quotes trimming and escape support, which will definitely cost more time.&lt;/p&gt;

&lt;p&gt;After all, I have tried my best to optimize it and the performance is also to my satisfaction. You can check using the &lt;a href="https://github.com/VowpalWabbit/vowpal_wabbit/tree/master/test/tools/parser_throughput"&gt;throughput tool&lt;/a&gt; for the &lt;a href="https://github.com/HollowMan6/vowpal_wabbit/tree/csv-old"&gt;unoptimized one&lt;/a&gt; during the project. And that was actually 10 times improvement!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VW text Parser:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2239418 bytes parsed in 60581μs
36.9657MB/s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Unoptimized CSV Parser:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1799450 bytes parsed in 912927μs
1.97108MB/s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Optimized CSV Parser:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1799450 bytes parsed in 87728μs
20.5117MB/s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My optimization mainly involves turn all the functions used by the parser into force inline. During the parsing, instead of parsing column by column, I categorize all the features by its namespace and parse those features by namespace to avoid double caculating the namespace hash. I also replace the map with unordered map, use vw's own data structure v_array to replace &lt;code&gt;std::vector&lt;/code&gt;, and use VW's realization of parsefloat to replace &lt;code&gt;std::stof&lt;/code&gt;, which is much faster. The statistics show that these really improved the performance a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;That's all, thanks for listening, and also special thanks to my mentors Jack Gerrits and Peter Chang from Microsoft Research - New York City Lab, who really helped me a lot during the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Comma-separated_values"&gt;Comma-separated values - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>machinelearning</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Tencent Rhino-bird Open-source Training Program 2022 – SunEC sm2p256v1 Key Pairs Generation</title>
      <dc:creator>Hollow Man</dc:creator>
      <pubDate>Sat, 13 Aug 2022 14:56:00 +0000</pubDate>
      <link>https://dev.to/hollowman6/tencent-rhino-bird-open-source-training-program-2022-sunec-sm2p256v1-key-pairs-generation-4lll</link>
      <guid>https://dev.to/hollowman6/tencent-rhino-bird-open-source-training-program-2022-sunec-sm2p256v1-key-pairs-generation-4lll</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fWADmQfS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hollowmansblog.files.wordpress.com/2022/08/e885bee8aeafe5bc80e6ba90e8b4a1e78caee88085e8af81e4b9a6tencentkonajdk-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fWADmQfS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hollowmansblog.files.wordpress.com/2022/08/e885bee8aeafe5bc80e6ba90e8b4a1e78caee88085e8af81e4b9a6tencentkonajdk-1.jpg" alt="" width="710" height="1008"&gt;&lt;/a&gt;&lt;br&gt;
For 2022 &lt;a href="https://mp.weixin.qq.com/s/E4dSpia0V9k5gtGl5T9cDg"&gt;final result&lt;/a&gt;, I passed the final evaluation, obtained all the honor titles (Only 2/4000+ in all participants): Tencent Open Source Contributor Certificate (only issued 30+ around the globe at that time), Intern of Excellence, Task Scholarship.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Tencent/OpenSourceTalent/issues/34"&gt;Issue&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Task 1
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.qq.com/doc/DUVpWUUVpVVVySVNw"&gt;Requirement&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/openjdk/jdk/pull/9541"&gt;https://github.com/openjdk/jdk/pull/9541&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Task 2
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.qq.com/doc/DUXhGSXBHZG11eUJ0"&gt;Requirement&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/HollowMan6/My-Tencent-Rhino-Bird-Open-Source-Training-Program/tree/main/2022-Kona-JDK/Task2/README.md"&gt;Result&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tested computing the signature as well as verifying the signature for comparing between &lt;code&gt;secp256r1&lt;/code&gt; and &lt;code&gt;secp256k1&lt;/code&gt; using SHA256withECDSA with the help of the SunEC provider.&lt;/p&gt;

&lt;p&gt;The result clearly shows that &lt;code&gt;secp256r1&lt;/code&gt; has a better performance than &lt;code&gt;secp256k1&lt;/code&gt; with regard to SHA256withECDSA when signing. But &lt;code&gt;secp256r1&lt;/code&gt; has almost the same performance as &lt;code&gt;secp256k1&lt;/code&gt; when verifying.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Benchmark                                 Mode  Cnt     Score    Error  Units
BenchmarkSigning.secp256k1_1024B         thrpt   25  1237.482 ± 30.518  ops/s
BenchmarkSigning.secp256k1_1024K         thrpt   25   318.589 ±  2.656  ops/s
BenchmarkSigning.secp256k1_128B          thrpt   25  1266.561 ± 32.311  ops/s
BenchmarkSigning.secp256k1_256B          thrpt   25  1254.327 ± 36.935  ops/s
BenchmarkSigning.secp256r1_1024B         thrpt   25  1746.453 ± 33.358  ops/s
BenchmarkSigning.secp256r1_1024K         thrpt   25   340.530 ±  3.970  ops/s
BenchmarkSigning.secp256r1_128B          thrpt   25  1763.460 ± 31.179  ops/s
BenchmarkSigning.secp256r1_256B          thrpt   25  1756.899 ± 32.715  ops/s
BenchmarkVerifying.secp256k1_1024B       thrpt   25   486.545 ± 13.410  ops/s
BenchmarkVerifying.secp256k1_1024K       thrpt   25   228.638 ±  2.478  ops/s
BenchmarkVerifying.secp256k1_128B        thrpt   25   491.065 ± 13.948  ops/s
BenchmarkVerifying.secp256k1_256B        thrpt   25   499.466 ±  4.558  ops/s
BenchmarkVerifying.secp256r1_1024B       thrpt   25   402.902 ± 53.489  ops/s
BenchmarkVerifying.secp256r1_1024K       thrpt   25   212.743 ± 23.301  ops/s
BenchmarkVerifying.secp256r1_128B        thrpt   25   401.215 ± 65.401  ops/s
BenchmarkVerifying.secp256r1_256B        thrpt   25   393.021 ± 79.755  ops/s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Further investigation shows that before &lt;code&gt;secp256k1&lt;/code&gt; was removed from JDK, all the curves seem to be realized by C using the OS library instead of Java. &lt;a href="https://github.com/openjdk/jdk/blob/jdk-11+28/src/jdk.crypto.ec/share/native/libsunec/impl/oid.c#L95"&gt;https://github.com/openjdk/jdk/blob/jdk-11+28/src/jdk.crypto.ec/share/native/libsunec/impl/oid.c#L95&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bugs.openjdk.org/browse/JDK-8238911"&gt;JDK-8238911&lt;/a&gt; in 2020 reported the weaknesses in the implementation of the native library EC code make it necessary to remove support for future releases. The most common EC curves (&lt;code&gt;secp256r1&lt;/code&gt;, &lt;code&gt;secp384r1&lt;/code&gt;, and &lt;code&gt;secp521r1&lt;/code&gt;) had been re-implemented in Java in the SunEC JCE provider.&lt;/p&gt;

&lt;p&gt;After some communications with my mentor Johns Jiang, he tells me that &lt;a href="https://bugs.openjdk.org/browse/JDK-8181594"&gt;JDK-8181594&lt;/a&gt; introduces the optimized finite field implementations in Java. Previously before that implementation was introduced, pure Java realization was really slow, then we use the OS library to realize all the curves so that the performance can be improved. But now, instead, with the help of that &lt;a href="https://mail.openjdk.org/pipermail/core-libs-dev/2018-February/051729.html"&gt;optimized Java library&lt;/a&gt;, Java realization takes the advantage and becomes the most efficient one, it's now even comparable with the pure C realization.&lt;/p&gt;

&lt;p&gt;Our flame graph also some kind confirms this, as you can see &lt;a href="https://github.com/HollowMan6/My-Tencent-Rhino-Bird-Open-Source-Training-Program/tree/main/2022-Kona-JDK/Task2/README.md#cpu"&gt;here&lt;/a&gt;, the Java Flight Recorder (JFR) can record the &lt;code&gt;secp256r1&lt;/code&gt; methods calling stacks, but it's not the case for &lt;code&gt;secp256k1&lt;/code&gt;. So it's likely that &lt;code&gt;secp256r1&lt;/code&gt; has a better performance than &lt;code&gt;secp256k1&lt;/code&gt; for signing since it's fully realized in Java and using that optimized library, thus reduces the calling costs for the OS library. If they are both realized in Java using the optimized method, I guess there should be no difference.&lt;/p&gt;

&lt;p&gt;As &lt;code&gt;secp256k1&lt;/code&gt; has already been removed in JDK and now &lt;code&gt;secp256r1&lt;/code&gt; does have a better performance, so I guess here we will have no obvious further room for improvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Task 3
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.qq.com/doc/DUVhpTE9HcVJmZFNF"&gt;Requirement&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.qq.com/doc/DUHNFbk96YnRXcGJH"&gt;The final report (in Chinese)&lt;/a&gt; is not limited to the following content, it also includes some more security analysis for different ways of realization.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/HollowMan6/My-Tencent-Rhino-Bird-Open-Source-Training-Program/tree/main/2022-Kona-JDK/Task3-SunEC"&gt;With modification of SunEC provider&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/HollowMan6/My-Tencent-Rhino-Bird-Open-Source-Training-Program/tree/main/2022-Kona-JDK/Task3-SunEC/README.md"&gt;Result&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As for Elliptic-curve based cryptography algorithms, the curve parameters are used to generate the keys.&lt;br&gt;
The official recommended curve parameters for SM2 can be seen here:&lt;br&gt;
&lt;a href="https://www.oscca.gov.cn/sca/xxgk/2010-12/17/1002386/files/b965ce832cc34bc191cb1cde446b860d.pdf"&gt;https://www.oscca.gov.cn/sca/xxgk/2010-12/17/1002386/files/b965ce832cc34bc191cb1cde446b860d.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That curve parameters is also known as &lt;code&gt;sm2p256v1&lt;/code&gt;, since it's also a prime curve just like &lt;code&gt;secp256r1&lt;/code&gt;, we can use the existing implementation of &lt;code&gt;secp256r1&lt;/code&gt; in the SunEC library to help us realize our implementation.&lt;/p&gt;

&lt;p&gt;The OID for &lt;code&gt;sm2p256v1&lt;/code&gt; is &lt;code&gt;1.2.156.10197.1.301&lt;/code&gt;: &lt;a href="http://gmssl.org/docs/oid.html"&gt;http://gmssl.org/docs/oid.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/HollowMan6/jdk/tree/sm2"&gt;https://github.com/HollowMan6/jdk/tree/sm2&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/HollowMan6/jdk/commit/c3e924641bb3a838f6abc496dd380ceb619df163"&gt;https://github.com/HollowMan6/jdk/commit/c3e924641bb3a838f6abc496dd380ceb619df163&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We first fill the curve parameters into the &lt;a href="https://github.com/HollowMan6/jdk/blob/c3e924641bb3a838f6abc496dd380ceb619df163/src/java.base/share/classes/sun/security/util/CurveDB.java#L258-L265"&gt;CurveDB&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then add the OID and names.&lt;/p&gt;

&lt;p&gt;The most important part is FieldGen. &lt;code&gt;FieldGen&lt;/code&gt; is used to automatically generate optimized finite field implementations, which is also the library I mentioned in Task 2 &lt;a href="https://bugs.openjdk.org/browse/JDK-8181594"&gt;JDK-8181594&lt;/a&gt; for improving Java version's efficiency. &lt;a href="https://github.com/HollowMan6/jdk/blob/c3e924641bb3a838f6abc496dd380ceb619df163/make/jdk/src/classes/build/tools/intpoly/FieldGen.java"&gt;https://github.com/HollowMan6/jdk/blob/c3e924641bb3a838f6abc496dd380ceb619df163/make/jdk/src/classes/build/tools/intpoly/FieldGen.java&lt;/a&gt; We need to generate two fields, &lt;code&gt;Integer Polynomial&lt;/code&gt; (corresponds to parameter &lt;code&gt;p&lt;/code&gt;) and &lt;code&gt;Order Field&lt;/code&gt; (corresponds to parameter &lt;code&gt;n&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;As:&lt;/p&gt;

&lt;p&gt;FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF&lt;/p&gt;

&lt;p&gt;=&lt;/p&gt;

&lt;p&gt;FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF $2^{256} - 1$&lt;/p&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;p&gt;00000001 00000000 00000000 00000000 00000000 00000000 00000000 &lt;br&gt;
00000000 $2^{224}$&lt;/p&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;p&gt;00000000 00000000 00000000 00000000 00000000 FFFFFFFF FFFFFFFF FFFFFFFF &lt;br&gt;
$2^{96} - 1$&lt;/p&gt;

&lt;p&gt;+&lt;/p&gt;

&lt;p&gt;00000000 00000000 00000000 00000000 00000000 00000000 FFFFFFFF FFFFFFFF&lt;/p&gt;

&lt;p&gt;$2^{64} - 1$&lt;/p&gt;

&lt;p&gt;= $2^{256} - 2^{224} - 2^{96} + 2^{64} - 2^0$&lt;/p&gt;

&lt;p&gt;So the &lt;code&gt;Integer Polynomial&lt;/code&gt; shall fill just like that. We can copy other parameters from &lt;code&gt;secp256r1&lt;/code&gt; as they are all 256 digit prime curve.&lt;/p&gt;

&lt;p&gt;The private keys in Hex can be printed directly with no special format.&lt;/p&gt;

&lt;p&gt;Since the public keys in Hex can be compressed, it does have a special format, that if it starts with &lt;code&gt;04&lt;/code&gt;, then the keys are uncompressed and we just then concat the X and Y coordinate together. The compressed ones always start with &lt;code&gt;02&lt;/code&gt; or &lt;code&gt;03&lt;/code&gt;, and then only the X coordinate is needed. The &lt;code&gt;02&lt;/code&gt; and &lt;code&gt;03&lt;/code&gt; is determined by that, when Y coordinate is even, we use &lt;code&gt;02&lt;/code&gt;, use &lt;code&gt;03&lt;/code&gt; when odd. In addition, we have to also make sure that both X and Y coordinates are 64 in length for Hex.&lt;/p&gt;

&lt;p&gt;As the Bouncy Castle library has already fully realized the SM2, to ensure that the generated keys fit the &lt;code&gt;sm2p256v1&lt;/code&gt;, I also use the generated keys for signing using SM3withSM2. The validity of the keys can be verified during the signature verification processes, during which we recover the &lt;code&gt;sm2p256v1&lt;/code&gt; elliptic curve point from the Bouncy Castle library based on the Hex format public key. If we use keys generated based on other curves, like &lt;code&gt;secp256r1&lt;/code&gt;, error will be thrown.&lt;/p&gt;

&lt;p&gt;Demo result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Public Key &lt;span class="o"&gt;(&lt;/span&gt;Uncompressed&lt;span class="o"&gt;)&lt;/span&gt;: 040A8FB35CA4761FAAA36B2A24E77EC657D96F74147C50EE2D5B50E3AAFD8304D8CBB65FB2E661D37B7C3B900E1BDBEDE894D9CBB9079E8DD704B9465BFF65EE17
Public Key: 030A8FB35CA4761FAAA36B2A24E77EC657D96F74147C50EE2D5B50E3AAFD8304D8
Private Key: 42756D22960A58D08F9E7E3A0D56D9630D8D051D082F4D2BFCE22FD2653524EB
To sign: How are you?
Signed: MEUCIAgvYgl0ydHwd536MkmwaRuhmkD/klh79VmHEBJI1zCRAiEAo9jNkGM+Tjh/0AmX82nSPOMYgRPaWm6SUXiB63YGAD4&lt;span class="o"&gt;=&lt;/span&gt;
Verification OK!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Error thrown when using &lt;code&gt;secp256r1&lt;/code&gt; (faulty key pairs):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Public Key &lt;span class="o"&gt;(&lt;/span&gt;Uncompressed&lt;span class="o"&gt;)&lt;/span&gt;: 0456A3205C7B47BF303F4B65CDAB5B94C343BE7220E5AAAB001B7263DBCD113B42447A9E41BF1374D4ABC7A2AE31E7441E3EB20D5808CCB7D88BFE4F8F2C9887C3
Public Key: 0356A3205C7B47BF303F4B65CDAB5B94C343BE7220E5AAAB001B7263DBCD113B42
Private Key: A33048CC39925B5D4BA4C34FE846C85D41DA5AABA0CFDE4092A7A4ED716D557
To sign: How are you?
Signed: MEYCIQCktncEmfLbC9rLC1Im9gj/AvZRUIQ5Z1plrq1X0L/5YwIhAOa0JeSoQFnV51kAJsFRY3T4cpCn2O7bKoN+M+nPpv6y
Exception &lt;span class="k"&gt;in &lt;/span&gt;thread &lt;span class="s2"&gt;"main"&lt;/span&gt; java.lang.IllegalArgumentException: Invalid point coordinates
        at org.bouncycastle.math.ec.ECCurve.validatePoint&lt;span class="o"&gt;(&lt;/span&gt;Unknown Source&lt;span class="o"&gt;)&lt;/span&gt;
        at org.bouncycastle.math.ec.ECCurve.decodePoint&lt;span class="o"&gt;(&lt;/span&gt;Unknown Source&lt;span class="o"&gt;)&lt;/span&gt;
        at org.sample.SM2Util.verify&lt;span class="o"&gt;(&lt;/span&gt;SM2Util.java:103&lt;span class="o"&gt;)&lt;/span&gt;
        at org.sample.SM2Util.main&lt;span class="o"&gt;(&lt;/span&gt;SM2Util.java:129&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JMH Performance test for compressed and uncompressed public key generation result shows that the compressed public keys generation has a better performance than the uncompressed ones. You can find the reason from the flame graph of Java Flight Recorder (JFR), that it's because the uncompressed ones also need to caculate the Y coordinate Hex format, which takes a lot of time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Benchmark                                         Mode  Cnt       Score       Error  Units
BenchmarkPublicKeys.sm2p256v1_compressed         thrpt   25  1212201.531 ± 248181.084  ops/s
BenchmarkPublicKeys.sm2p256v1_uncompressed       thrpt   25   760033.805 ±  35058.515  ops/s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;a href="https://github.com/HollowMan6/My-Tencent-Rhino-Bird-Open-Source-Training-Program/tree/main/2022-Kona-JDK/Task3"&gt;Homemade&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Our realization refers to the JavaScript implementation &lt;a href="https://github.com/wechat-miniprogram/sm-crypto/tree/master/src/sm2"&gt;here&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication"&gt;Wikipedia Elliptic curve point multiplication&lt;/a&gt; and the &lt;a href="https://www.oscca.gov.cn/sca/xxgk/2010-12/17/1002386/files/b791a9f908bb4803875ab6aeeb7b4e03.pdf"&gt;official documentation&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;The homemade one is based on purely mathematical methods, no other dependencies.&lt;/p&gt;

&lt;p&gt;We use &lt;a href="https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator"&gt;SecureRandom&lt;/a&gt; to generate the private key, we also tried public key generation using the Standard Projective Coordinates and Jacobian Coordinates, as well as the binary expansion and addminus algorithm.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/HollowMan6/My-Tencent-Rhino-Bird-Open-Source-Training-Program/tree/main/2022-Kona-JDK/Task3/README.md"&gt;result&lt;/a&gt; for more performance comparisons.&lt;/p&gt;

&lt;p&gt;JMH Performance test for compressed and uncompressed public key generation result shows that the uncompressed public keys generation has almost the same performance as the compressed ones. Though it seems like a contradiction, here the uncompressed Y coordinate Hex caculation counts significantly smaller when you take the overall time into consideration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Benchmark                                         Mode  Cnt       Score       Error  Units
BenchmarkPublicKeys.sm2p256v1_compressed         thrpt   25  786.038 ± 12.099  ops/s
BenchmarkPublicKeys.sm2p256v1_uncompressed       thrpt   25  795.960 ±  8.557  ops/s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>opensource</category>
      <category>java</category>
    </item>
    <item>
      <title>My Google Summer of Code 2022 – Google Blockly Workspace MultiSelect Plugin</title>
      <dc:creator>Hollow Man</dc:creator>
      <pubDate>Sat, 13 Aug 2022 14:44:58 +0000</pubDate>
      <link>https://dev.to/hollowman6/my-google-summer-of-code-2022-google-blockly-workspace-multiselect-plugin-bn7</link>
      <guid>https://dev.to/hollowman6/my-google-summer-of-code-2022-google-blockly-workspace-multiselect-plugin-bn7</guid>
      <description>&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=4OFU9D1Y2DI"&gt;My Presentation at 2023 Blockly Developer Summit: Multi-Select Plugin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More about &lt;a href="https://sites.google.com/view/2023blocklysummit/speakers-organizers"&gt;2023 Blockly Summit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OSWIhpdM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hollowmansblog.files.wordpress.com/2022/08/completion_certificate_2022_contributor-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OSWIhpdM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hollowmansblog.files.wordpress.com/2022/08/completion_certificate_2022_contributor-1.jpg" alt="" width="800" height="619"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--51e7OjPM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hollowmansblog.files.wordpress.com/2022/08/gsoc-mit.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--51e7OjPM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hollowmansblog.files.wordpress.com/2022/08/gsoc-mit.png%3Fw%3D1024" alt="" width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mit-cml/workspace-multiselect"&gt;Project Repository Link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hollowman.ml/workspace-multiselect/"&gt;Try out the plugin online&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PRs and issues resolved during GSoC 2022:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/mit-cml/workspace-multiselect/pull/1"&gt;PR #1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mit-cml/workspace-multiselect/pull/2"&gt;PR #2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mit-cml/workspace-multiselect/issues/3"&gt;Issue #3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mit-cml/workspace-multiselect/pull/4"&gt;PR #4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mit-cml/workspace-multiselect/pull/5"&gt;PR #5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/google/blockly-samples/pull/1202"&gt;google/blockly-samples PR #1202&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ThibaultJanBeyer/DragSelect/pull/128"&gt;ThibaultJanBeyer/DragSelect PR #128&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/HollowMan6"&gt;My GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://groups.google.com/g/blockly/c/1qb-M8HZYzY"&gt;Mailing list for tracking&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hi there! If you prefer watching videos, check this out for an episode demoing the plugin: &lt;a href="https://www.youtube.com/watch?v=FZyvvPZhIRs"&gt;https://www.youtube.com/watch?v=FZyvvPZhIRs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For you guys who prefer reading, in this blog post I will introduce you to my work on the plugin for selecting, dragging, and doing actions on multiple blocks. &lt;a href="https://summerofcode.withgoogle.com/programs/2022/projects/9wF06HWE"&gt;The project&lt;/a&gt; is sponsored by Google Summer of Code (GSoC) 2022, under MIT App inventor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backgrounds
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Aim
&lt;/h3&gt;

&lt;p&gt;The project aims to enable the selection of multiple blocks at the same time and allow moving and doing actions on multiple blocks on Blockly.&lt;/p&gt;

&lt;p&gt;This behavior is the same as when you try to manage your files on your Operating System. You can click on the files while pressing the control key, drag a rectangle to select multiple files. Then move them around, copying and deleting.&lt;/p&gt;

&lt;p&gt;It sounds a little bit easy, but actually, I would say that it's not. Multiple selections can become a crazy-complex feature when you start thinking about the details.&lt;/p&gt;

&lt;h3&gt;
  
  
  History
&lt;/h3&gt;

&lt;p&gt;This &lt;a href="https://github.com/google/blockly-samples/issues/267"&gt;feature request&lt;/a&gt; has remained open on GitHub Issues for six years. However, it was still in the discussion phase and far from the beginning of Implementation before my project began.&lt;/p&gt;

&lt;p&gt;Since the Blockly community long &lt;a href="https://groups.google.com/g/blockly/c/A9DB5Z0VXEs/m/Xns0L50JBQAJ"&gt;wants this feature&lt;/a&gt;, we base our plugin on the latest Blockly so that it can be applied to everyone's project. The App Inventor uses &lt;a href="https://github.com/mit-cml/blockly/tree/master"&gt;a Blockly version&lt;/a&gt; that is much older, so it's a pity that we can't see it work on App Inventor now. Let's hope that the App Inventor can upgrade the Blockly version to the latest soon.&lt;/p&gt;

&lt;h3&gt;
  
  
  Realization
&lt;/h3&gt;

&lt;p&gt;The "drag a rectangle to select" feature is realized with the help of the &lt;a href="https://dragselect.com/"&gt;DragSelect plugin&lt;/a&gt;. I submitted &lt;a href="https://github.com/ThibaultJanBeyer/DragSelect/pull/128"&gt;a PR&lt;/a&gt; to add the pointer-events so that it can work for Blockly, and it got merged into &lt;a href="https://github.com/ThibaultJanBeyer/DragSelect/releases/tag/v2.4.4"&gt;v2.4.4&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In addition, I disable the drag surface feature in Blockly, which stops us from moving multiple blocks simultaneously. Also, there's &lt;a href="https://github.com/google/blockly/issues/6160"&gt;evidence&lt;/a&gt; suggesting that we can perform better without a drag surface.&lt;/p&gt;

&lt;p&gt;So, how does the plugin work? Well, generally, the plugin acts like an adapter. It maintains its own multiple selection set, which keeps currently selected blocks and make sure we always have one of the selected blocks as the selected one in Blockly core. When users do some actions, the plugin also passes all the actions to the other blocks in our set besides the selected one in Blockly core.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functionalities
&lt;/h2&gt;

&lt;p&gt;Let's check out what the plugin can do!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Additional blocks can be selected by holding the SHIFT key while clicking the new block. You can also deselect the block by clicking the already selected block.&lt;/li&gt;
&lt;li&gt;Clicking on the button above the trashcan is equivalent to holding or releasing the SHIFT key for switching between the multiple selection mode and the normal mode.&lt;/li&gt;
&lt;li&gt;We can clear the selection by clicking on the workspace background.&lt;/li&gt;
&lt;li&gt;Clicking a new block without holding SHIFT key can clear the multiple selections and change the selection to only that block.&lt;/li&gt;
&lt;li&gt;Holding SHIFT key to drag a rectangle area to select can reverse their selection state for the blocks touched by the rectangle.&lt;/li&gt;
&lt;li&gt;In multiple selection mode, workspace dragging and block dragging will all be disabled. You can only drag to draw a rectangle for selection.&lt;/li&gt;
&lt;li&gt;When some of the selected blocks are in one block stack, for example, some top blocks and some of their children blocks are in the selection simultaneously. If applicable, the plugin only disconnects the selected most top block in that stack with its parent block. Move along with all the children's blocks of that most top block as a whole.&lt;/li&gt;
&lt;li&gt;You can also drag all the blocks to the trash can.&lt;/li&gt;
&lt;li&gt;When you edit the fields while selecting multiple blocks, we will automatically apply that to all the blocks with the same type.&lt;/li&gt;
&lt;li&gt;There's also an MIT App Inventor-only feature that has been migrated into this plugin, that you can double click to collapse or expand currently selected blocks.&lt;/li&gt;
&lt;li&gt;For the context menu, the &lt;code&gt;Duplicate&lt;/code&gt; will duplicate the selected most top block in the block stack and all the children blocks of that most top block. The selection will be changed to all newly created duplicate blocks' most top blocks. For all the other items, The actions to show are determined by the state of the block which the user right-clicks on, and the same action will be applied to all the blocks no matter their individual state. We will append the currently applicable number of user-selected state-changing blocks, and the number will only be shown when it is greater than 1.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Add Comment&lt;/code&gt; / &lt;code&gt;Remove Comment&lt;/code&gt; option will add / remove comment buttons to all the selected blocks.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Inline Inputs&lt;/code&gt; / &lt;code&gt;External Inputs&lt;/code&gt; option will convert the input format with all the selected blocks.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Collapse Block&lt;/code&gt; / &lt;code&gt;Expand Block&lt;/code&gt; option will only apply to the selected most top block in the block stack.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Disable Block&lt;/code&gt; / &lt;code&gt;Enable Block&lt;/code&gt; option will only apply to the selected most top block in the block stack. All the children blocks of that most top block will also get disabled.&lt;/li&gt;
&lt;li&gt;The number in &lt;code&gt;Delete [X] Blocks&lt;/code&gt; is the count of the selected most top block in the block stack as well as all children of those selected most top block. Clicking on that option will delete the blocks mentioned.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Help&lt;/code&gt; option displays just the helping information of the block the user just right-clicked on.&lt;/li&gt;
&lt;li&gt;We add &lt;code&gt;Select all Blocks&lt;/code&gt; in the workspace context menu.&lt;/li&gt;
&lt;li&gt;For the shortcut keys, These actions will only apply to the selected most top block in the block stack. when you press &lt;code&gt;Ctrl A&lt;/code&gt;, you can select all the blocks in the current workspace. &lt;code&gt;Ctrl C&lt;/code&gt; to copy the selected blocks, &lt;code&gt;Ctrl X&lt;/code&gt; to cut the selected blocks to the clipboard, and &lt;code&gt;Ctrl V&lt;/code&gt; to paste all the blocks currently in the clipboard and get all the newly pasted blocks selected. &lt;/li&gt;
&lt;li&gt;Bumping neighbors after dragging to avoid overlapping is disabled in this plugin by default, since I find it disturbing sometimes for multiple selections.&lt;/li&gt;
&lt;li&gt;Click on a block will bring that block to the front in case Bumping neighbours is disabled.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;If you want to integrate the plugin into your project, you can add the dependency into your &lt;code&gt;package.json&lt;/code&gt;. In the source code, pass the workspace to the plugin, and initialize the plugin, and then it's done! You can choose to disable double-click the blocks to collapse or expand and enable bumping neighbors after dragging to avoid overlapping. For the multi-select controls, you can also choose to hide the icon and customize the icons of each state. More details can be found in the &lt;a href="https://github.com/mit-cml/workspace-multiselect#readme"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also choose to integrate the plugin with other ones, like the &lt;a href="https://github.com/google/blockly-samples/tree/master/plugins/scroll-options"&gt;scroll options&lt;/a&gt;, which enable the edge scroll and wheel scroll for Blockly. The only thing you have to pay attention for the scroll options plugin to work is to assign the original &lt;code&gt;blockDragger&lt;/code&gt; value required for scroll options to &lt;code&gt;baseBlockDragger&lt;/code&gt; in our plugin. During the project period I also submitted &lt;a href="https://github.com/google/blockly-samples/pull/1202"&gt;a PR&lt;/a&gt; for fixing the a bug that makes scroll options unable to work without the drag surface, and it has already got merged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;That's all for this blog post. Before it ends, I would like to say thank you to my mentors, Evan Patton and Li Li, as well as the MIT App Inventor Team for guiding me throughout the project. They are really supportive. Also, special Thanks to Beka Westberg. She devoted a lot of time to giving suggestions and helping review the code. We can't have this plugin without her! Finally, thanks for reading this blog post! If you have any questions, please comment, and I'll reply. Cheers!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>My Summer of Bitcoin 2022 Project - CI for CADR</title>
      <dc:creator>Hollow Man</dc:creator>
      <pubDate>Sat, 13 Aug 2022 14:03:00 +0000</pubDate>
      <link>https://dev.to/hollowman6/my-summer-of-bitcoin-2022-project-ci-for-cadr-2pid</link>
      <guid>https://dev.to/hollowman6/my-summer-of-bitcoin-2022-project-ci-for-cadr-2pid</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_C0-VkSj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hollowmansblog.files.wordpress.com/2022/08/summer-of-bitcoin-2022.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_C0-VkSj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hollowmansblog.files.wordpress.com/2022/08/summer-of-bitcoin-2022.jpg" alt="" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Synopsis
&lt;/h2&gt;

&lt;p&gt;Before the &lt;a href="https://www.summerofbitcoin.org/project-ideas-details?recordId=recaklAlmMd5cHfdq"&gt;Summer of Bitcoin&lt;/a&gt; project, &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder"&gt;Cryptoanarchy Debian Repo (CADR)&lt;/a&gt; lacked Continuous Integration (CI), which troubles the new coming contributors because setting up the developing environment can be complex. I finally successfully implemented the CI using GitHub Actions default runners. The CI can be triggered manually, or by sending PRs as well as pushing directly to the master branch.&lt;/p&gt;

&lt;p&gt;The CI is divided into 2 jobs: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first one is the build job. It builds the running podman environment image, uploads the image to Artifacts for reuse. Then with the podman environment, builds the CADR packages, checks their sha256 sum, and then uploads the built Debian packages as well as their sha256 sum values to Artifacts.&lt;/li&gt;
&lt;li&gt;The second one is the test job. It runs when the build job finishes. The testing jobs are run in parallel for each package. The test job first downloads the built images and packages Artifacts uploaded in the build job, then use &lt;code&gt;make test-here-basic-%&lt;/code&gt; and &lt;code&gt;make test-here-upgrade-%&lt;/code&gt;(% for package name) to run tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Road of Implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  First try
&lt;/h3&gt;

&lt;p&gt;At first, I ignored the fact that there &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/tree/master/docker"&gt;already exists a dockerfile&lt;/a&gt; for CADR running (although it was not for building), and setup &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/commit/1580e9e025f7ccb597b35753e004a7d5327f10ef"&gt;my own dockerfile&lt;/a&gt; from scratch by adding dependencies when I encounter any errors. &lt;/p&gt;

&lt;p&gt;My own dockerfile turned out to work fine on GitHub Actions for the building process, but failed for the test process.&lt;br&gt;
Initially I thought it was some more dependency issues, since the test can work on my own computer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2_Uj3LCo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/a555b51e82504433bc209712b326a615.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2_Uj3LCo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/a555b51e82504433bc209712b326a615.png" alt="" width="691" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When checking the logs I found that it's due to the unshare issue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UX-qiG9F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/1cd9fb66d1e042abbe920aa69458cf61.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UX-qiG9F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/1cd9fb66d1e042abbe920aa69458cf61.png" alt="" width="690" height="303"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DrxJmr4F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/790d483263614dd98b4e7ac85c485595.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DrxJmr4F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/790d483263614dd98b4e7ac85c485595.png" alt="" width="763" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I noticed that adding a &lt;code&gt;--privileged&lt;/code&gt; parameter can fix the unshare issue for docker. But then a systemd issue just came after it. Finally I noticed the dockerfile in the codebase that already exists for CADR, and just as how it works, I made the systemd to start as the first process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;VOLUME&lt;/span&gt;&lt;span class="s"&gt; [ "/sys/fs/cgroup" ]&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["/lib/systemd/systemd"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and add &lt;code&gt;--tmpfs /tmp --tmpfs /run --tmpfs /run/lock -v /sys/fs/cgroup:/sys/fs/cgroup:ro&lt;/code&gt; as additional parameters to share some host machine resources and make it as the daemon container. Operations are done using docker exec to attach to the container. But still it doesn’t fix the systemd issue.&lt;/p&gt;

&lt;p&gt;Finally I switched to podman and the systemd issue got fixed (it supports &lt;code&gt;--systemd=true&lt;/code&gt;) because I occasionally found &lt;a href="https://developers.redhat.com/blog/2019/04/24/how-to-run-systemd-in-a-container"&gt;this article&lt;/a&gt; when I Googled the issue.&lt;/p&gt;

&lt;p&gt;However, a new issue occurs suggesting failed to override dbcache.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cciJbvtU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/a5283aca019d4103b144765555134a6c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cciJbvtU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/a5283aca019d4103b144765555134a6c.png" alt="" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Can't see any errors from the workflow logs, even though the missing bc dependency has been fixed and I can confirm that &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/blob/f60cbc8d5bb4fc94c653cabbfb1e7de0adffc4be/pkg_specs/bitcoin-@variant.sps#L88"&gt;the command here&lt;/a&gt; works correctly in the container running on my PC. Moreover when I manually skip the test just mentioned, the test further shows that there is an unneeded reindex:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EX9ZEWV3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/37b06ec8572a4616a499d743b9af4fdd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EX9ZEWV3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/37b06ec8572a4616a499d743b9af4fdd.png" alt="" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which suggests that it's related to &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/issues/108"&gt;issue 108&lt;/a&gt; maybe? Have opened &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/issues/202"&gt;an issue here&lt;/a&gt;. I can skip that test, but further error suggesting electrs is not available. It can be fixed with &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/203"&gt;this PR&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7z004heI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/a6658b680e5446f6871a25319dfbfeeb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7z004heI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/a6658b680e5446f6871a25319dfbfeeb.png" alt="" width="455" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even if those issues are fixed, another platform may still be needed since the full test requires too much space:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SxWu91zu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/cae7728b10214519bd25cf3748417448.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SxWu91zu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/cae7728b10214519bd25cf3748417448.png" alt="" width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Only testing the regtest part will be fine with no space issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fixing the tests
&lt;/h3&gt;

&lt;p&gt;The first issue is to find out why overriding dbcache fails. This takes me quite a few weeks to find out &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/issues/199"&gt;the solution&lt;/a&gt;. Originally, when determining bitcoin dbcache size, &lt;code&gt;bc&lt;/code&gt; is invoked. But &lt;code&gt;bc&lt;/code&gt; is not guaranteed to be installed, thus it can fail. Then instead of doing maths wizardry, I &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/200"&gt;submitted a PR&lt;/a&gt; to just match on ranges: &lt;code&gt;RAM &amp;lt; 1024&lt;/code&gt; -&amp;gt; &lt;code&gt;default dbcache&lt;/code&gt;, &lt;code&gt;RAM &amp;lt; 2048&lt;/code&gt; -&amp;gt; &lt;code&gt;dbcache=512&lt;/code&gt;, ..., &lt;code&gt;RAM =&amp;gt; 8192&lt;/code&gt; -&amp;gt; &lt;code&gt;dbcache=4096&lt;/code&gt;. However, the failed to override dbcache still exists when running in GitHub Actions workflow with this PR. It's very weird, as when I run the test manually using the same methods from the workflow with the podman container on my PC, such an issue won't appear. So the issue seems to belong to GitHub Actions workflow environment only even though it's running in the container.&lt;/p&gt;

&lt;p&gt;Then after a lot of trial and error, I finally found the culprit. By &lt;a href="https://github.com/SinusBot/docker/pull/40"&gt;referring to PR&lt;/a&gt;, previously the debcrafter dropped all capabilities which seems to cause errors when the host kernel capabilities do not match those known to &lt;code&gt;setpriv&lt;/code&gt;. We need to only drop supported capabilities by the current kernel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SKkjlpgn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/1b152561e4614738840551c91d92a07b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SKkjlpgn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://img-blog.csdnimg.cn/1b152561e4614738840551c91d92a07b.png" alt="" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I &lt;a href="https://github.com/Kixunil/debcrafter/pull/52"&gt;submitted a PR&lt;/a&gt; to fix this, and got merged.&lt;/p&gt;

&lt;p&gt;The second issue is to find out why the unneeded reindex error exists. I noticed that although the test failed on &lt;code&gt;test-here-basic-electrs&lt;/code&gt; with unneeded reindex when running make test, running &lt;code&gt;make test-here-basic-electrs&lt;/code&gt; alone won't fail. So prior to fixing this issue, my guess was that maybe it's still related to issue &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/issues/108"&gt;issue 108&lt;/a&gt;, which is that after updating existing non-pruned nodes in experimental &lt;code&gt;-reindex&lt;/code&gt; was used despite pruning not being changed. Or the test environment didn't get cleaned up before &lt;code&gt;test-here-basic-electrs&lt;/code&gt; when executing make test. My final result proves that the later is right, and &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/204"&gt;submitted a PR&lt;/a&gt; to clean up the chain mode marker, since we want it to be clean with package_clean_install.sh&lt;/p&gt;

&lt;p&gt;I also submitted &lt;a href="https://github.com/Kixunil/debcrafter/pull/53"&gt;a PR&lt;/a&gt; to force linked-hash-map version to be 0.5.4 for fixing the build issue of debcrafter that just came up during the project period.&lt;/p&gt;

&lt;p&gt;The test can be successful on GitHub Actions when only tested with regtest and after &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/200"&gt;PR 200&lt;/a&gt;, &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/201"&gt;201&lt;/a&gt;, &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/203"&gt;203&lt;/a&gt;, &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/204"&gt;204&lt;/a&gt; get merged.&lt;/p&gt;

&lt;h3&gt;
  
  
  Research on cloud provider
&lt;/h3&gt;

&lt;p&gt;I also researched on which cloud service to use, as we were intended to use a GItHub self-hosted runner. As I checked on cloud service providers AWS, Google Cloud and Azure. I find that GitHub Actions uses Azure as their &lt;a href="https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#cloud-hosts-used-by-github-hosted-runners"&gt;default runners&lt;/a&gt;, to build a GitHub self-hosted runner, Azure would be a good choice if we use the same provider as the GitHub default hosted runner. Also Azure has a &lt;a href="https://azure.microsoft.com/en-us/free/"&gt;trial period&lt;/a&gt; with 200 dollars for one month when starting a new account, so we can start free, while other cloud service providers don’t offer such a great discount.&lt;/p&gt;

&lt;h3&gt;
  
  
  Investigation on other possible CI platforms
&lt;/h3&gt;

&lt;p&gt;I find out that unlike GitHub Actions that runs CI in a virtual machine, Travis CI, GitLab CI/CD, Jenkins all run the CI predefined Docker containers without &lt;a href="https://stackoverflow.com/a/61705398/14343335"&gt;without systemd support&lt;/a&gt;. Then it would be not possible to run a systemd supported podman container inside such a container. Azure DevsOps is a valid one for our use case, and I also tried to &lt;a href="https://dev.azure.com/HollowMan6/cryptoanarchy-deb-repo-builder/_build/results?buildId=30&amp;amp;view=results"&gt;use it&lt;/a&gt;. Then I noticed that for a single CI job, each step, it only allows 1 hour maximum, otherwise it would &lt;a href="https://dev.azure.com/HollowMan6/cryptoanarchy-deb-repo-builder/_build/results?buildId=35&amp;amp;view=logs&amp;amp;j=12f1170f-54f2-53f3-20dd-22fc7dff55f9"&gt;get cancelled&lt;/a&gt;, while our build job as well as full net test job last much longer than 1 hour, it's also not suitable for us. Then finally the GitHub Actions would be the only good choice to have.&lt;/p&gt;

&lt;h3&gt;
  
  
  Self-hosted runners for GitHub Actions
&lt;/h3&gt;

&lt;p&gt;I had also tried to use Azure Virtual Machines service by myself to set up Self-hosted runners for GitHub Actions, but it seems like the environment doesn't automatically get cleaned each time, and is contaminated from previous runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Divide and Conquer
&lt;/h3&gt;

&lt;p&gt;Finally I came up with a new way for testing. We can use the divide and conquer to bypass the short of disk space issue as well as the contaminated running environment issue when running tests on both the mainnet and regtest. I can see that the make test is composed of make test-here-basic-% and make test-here-upgrade-%(% for package name), we can just use &lt;a href="https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#using-a-matrix-strategy"&gt;the matrix&lt;/a&gt; in GitHub Actions to test each package in separate environments, and then the disk space would be enough, and &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/204"&gt;PR 204&lt;/a&gt; can be closed because we now always have a clean environment.&lt;/p&gt;

&lt;p&gt;Then I successfully implemented and tested that method, and it works! So right now it's the full test and I have reached the project goal with even a solution that has no money cost for CI building and testing!&lt;/p&gt;

&lt;p&gt;The CI can be successful if the previous tests fixing PRs get merged first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Deliverables
&lt;/h2&gt;

&lt;p&gt;After my mentor &lt;a href="https://github.com/Kixunil"&gt;@Kixunil&lt;/a&gt;'s review, I began to use &lt;code&gt;--locked&lt;/code&gt; parameter to make cargo use &lt;code&gt;cargo.lock&lt;/code&gt; which contains correct versions. Also I fixed a security issue, make a user account &lt;code&gt;user&lt;/code&gt; and built/tested with &lt;code&gt;user&lt;/code&gt;, and made to upload the sha256sum result for the built deb packages afterwards so people can check hashes.&lt;/p&gt;

&lt;p&gt;In addition, I fixed tests for bitcoin-regtest after setting bitcoind nosettings enabled in &lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/205"&gt;PR 205&lt;/a&gt;. Then there should be some kind of bug in core for this wallet location difference in the GitHub runner and the physical machine, so the PR gets closed and another solution that makes tests independent of wallet location was committed.&lt;/p&gt;

&lt;p&gt;The CI runs successfully with the above changes, and everything works fine, nothing left to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;My Summer of Bitcoin project is a great experience for me as I learned a lot about Bitcoin and related DevOps knowledge.&lt;/p&gt;

&lt;p&gt;If you are interested in Bitcoin and would like to start contributing to Cryptoanarchy Debian, with my work, you can easily fork the repo and add more test or new packages by committing the code to your fork's master branch on GitHub, the CI will help you build the deb packages and locate possible errors, no need to setup the developing environment on your computer again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary of PRs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Merged
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/198"&gt;[SoB] Add GitHub workflow for CI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Kixunil/debcrafter/pull/52"&gt;Fix libcap-ng is too old for 'all' caps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/200"&gt;Remove bc dependency for overriding dbcache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/201"&gt;Change all apt into apt-get in test&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/203"&gt;Try more times to test connecting to electrs-regtest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/196"&gt;Set bitcoind log file under /var/log&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/197"&gt;Set bitcoind nosettings enabled by default&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Closed as resolved in another way
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/issues/202"&gt;(Issue) Bug: Test failed for bitcoin-regtest with error unneeded reindex for test-here-basic-electrs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/204"&gt;Fix unneeded reindex error running tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/debian-cryptoanarchy/cryptoanarchy-deb-repo-builder/pull/205"&gt;Fix tests for bitcoin-regtest after setting bitcoind nosettings enabled&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Kixunil/debcrafter/pull/53"&gt;Force linked-hash-map version to be 0.5.4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/debian-cryptoanarchy/cadr-guide/pull/14"&gt;rustyline downgrade to 6.3.0 to fix compiling issue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Schedule notifications on WeChat with Azure AKS</title>
      <dc:creator>Hollow Man</dc:creator>
      <pubDate>Sun, 06 Mar 2022 06:35:50 +0000</pubDate>
      <link>https://dev.to/hollowman6/schedule-notifications-on-wechat-with-azure-aks-j05</link>
      <guid>https://dev.to/hollowman6/schedule-notifications-on-wechat-with-azure-aks-j05</guid>
      <description>&lt;h3&gt;
  
  
  Overview of My Submission
&lt;/h3&gt;

&lt;p&gt;An application that allows you to schedule notifications on &lt;a href="https://en.wikipedia.org/wiki/WeChat"&gt;WeChat&lt;/a&gt; so that you can get notified while keep connected with your friends.&lt;/p&gt;

&lt;p&gt;This app is realized through several WeChat message push platforms, such as &lt;a href="https://www.pushplus.plus/"&gt;PushPlus&lt;/a&gt; and &lt;a href="https://sct.ftqq.com/"&gt;ServerChan&lt;/a&gt;, as well as the native Enterprise version of WeChat (WeCom) message push API.&lt;/p&gt;

&lt;p&gt;The application be deployed using Azure AKS by helm chat with this &lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message/blob/main/helmChart/install-online.sh"&gt;script&lt;/a&gt;. For meanings of configurations please refer to the &lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message#online-install-scriptrecommend"&gt;README file&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category: Computing Captains
&lt;/h3&gt;

&lt;h3&gt;
  
  
  Link to Code on GitHub
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HollowMan6"&gt;
        HollowMan6
      &lt;/a&gt; / &lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message"&gt;
        Wechat-Timed-Message
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Send timed message to Wechat. (向微信推送定时消息)
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
向微信推送定时消息&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://hub.docker.com/repository/docker/hollowman6/send-message-to-wechat" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/1f4cf1f99247e514c0452a504f358afe7ff0af88c89e55bcf32e4f5b87943d63/68747470733a2f2f646f636b6572692e636f2f696d6167652f686f6c6c6f776d616e362f73656e642d6d6573736167652d746f2d776563686174" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message/graphs/commit-activity"&gt;&lt;img src="https://camo.githubusercontent.com/8645276a4175dfd89bec9ccdbd853edd47145d2d6f1ed71150cde59c903d7eab/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f486f6c6c6f774d616e362f5765636861742d54696d65642d4d657373616765" alt="last-commit"&gt;&lt;/a&gt;
&lt;a href="https://artifacthub.io/packages/search?repo=wechat-timed-message" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/83feffc70f45f86bdfb3fb2d6706a8f034378ca809820bfbde4d450dc5f7e851/68747470733a2f2f696d672e736869656c64732e696f2f656e64706f696e743f75726c3d68747470733a2f2f61727469666163746875622e696f2f62616467652f7265706f7369746f72792f7765636861742d74696d65642d6d657373616765" alt="Artifact HUB"&gt;&lt;/a&gt;
&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message/releases"&gt;&lt;img src="https://camo.githubusercontent.com/aaeae556c54f9c2994e3cc617637b0e0d0d8438edbcfe5d079efecd73ac7e320/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652d646174652f486f6c6c6f774d616e362f5765636861742d54696d65642d4d657373616765" alt="release-date"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Message/workflows/Python%20package/badge.svg"&gt;&lt;img src="https://github.com/HollowMan6/Wechat-Timed-Message/workflows/Python%20package/badge.svg" alt="Python package"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/HollowMan6?tab=followers"&gt;&lt;img src="https://camo.githubusercontent.com/8441e22aa4e54675be52375e55951f0aaa6d809964cf71479073768aec57bfd4/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f666f6c6c6f776572732f486f6c6c6f774d616e363f7374796c653d736f6369616c" alt="Followers"&gt;&lt;/a&gt;
&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message/watchers"&gt;&lt;img src="https://camo.githubusercontent.com/241dde16dcd7d54f90feada1e9bad40d5e27309fd3a279d5f232cfb3f25f33ec/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f77617463686572732f486f6c6c6f774d616e362f5765636861742d54696d65642d4d6573736167653f7374796c653d736f6369616c" alt="watchers"&gt;&lt;/a&gt;
&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message/stargazers"&gt;&lt;img src="https://camo.githubusercontent.com/da93471395688e85725524123b41721e1897fdcad100678668fa71f84986fc5a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f486f6c6c6f774d616e362f5765636861742d54696d65642d4d6573736167653f7374796c653d736f6369616c" alt="stars"&gt;&lt;/a&gt;
&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message/network/members"&gt;&lt;img src="https://camo.githubusercontent.com/e2c272eb01adfc47036a32a57b3f10da7fb5f0c591a3549e214c9e82d61b7412/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f666f726b732f486f6c6c6f774d616e362f5765636861742d54696d65642d4d6573736167653f7374796c653d736f6369616c" alt="forks"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://hollowman6.github.io/fund.html" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/b527a02f3970d48aa1570c5757c89e88d995616c74259938691a86d0ca26aad0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2545322539442541342532304f70656e253230536f757263652d477265656e3f7374796c653d666c61742d737175617265266c6f676f3d476974687562266c6f676f436f6c6f723d7768697465266c696e6b3d68747470733a2f2f686f6c6c6f776d616e362e6769746875622e696f2f66756e642e68746d6c" alt="Open Source Love"&gt;&lt;/a&gt;
&lt;a href="https://opensource.org/licenses/GPL-3.0/" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/2f706a3275e4a48dc85ec930933303f3417d3b91d20943e25c8b66acdd223d53/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d47504c2d626c7565" alt="GPL Licence"&gt;&lt;/a&gt;
&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message/archive/master.zip"&gt;&lt;img src="https://camo.githubusercontent.com/2d740b5a03a6bd88120801d0b3d379f3bc5eca889ad30d8cbc3153afdbdf6e2b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f7265706f2d73697a652f486f6c6c6f774d616e362f5765636861742d54696d65642d4d6573736167652e737667" alt="Repo-Size"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://lgtm.com/projects/g/HollowMan6/Wechat-Timed-Message/alerts/" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/c40c98644d6acfe83bf739494cd271915a4450d9860db57c5d85dac7449a9a2e/68747470733a2f2f696d672e736869656c64732e696f2f6c67746d2f616c657274732f672f486f6c6c6f774d616e362f5765636861742d54696d65642d4d6573736167652e7376673f6c6f676f3d6c67746d266c6f676f57696474683d3138" alt="Total alerts"&gt;&lt;/a&gt;
&lt;a href="https://lgtm.com/projects/g/HollowMan6/Wechat-Timed-Message/context:python" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/6975682a1fa7b8b1d568348c09c7fa77cf0681395142319e7059d7fdd9c38cf6/68747470733a2f2f696d672e736869656c64732e696f2f6c67746d2f67726164652f707974686f6e2f672f486f6c6c6f774d616e362f5765636861742d54696d65642d4d6573736167652e7376673f6c6f676f3d6c67746d266c6f676f57696474683d3138" alt="Language grade: Python"&gt;&lt;/a&gt;
&lt;a href="https://microbadger.com/images/hollowman6/send-message-to-wechat" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/d89d2f7ef74ba5245271a89f382b71c512577d2fe2f27bf1ec247224a6b61351/68747470733a2f2f696d616765732e6d6963726f6261646765722e636f6d2f6261646765732f696d6167652f686f6c6c6f776d616e362f73656e642d6d6573736167652d746f2d7765636861742e737667" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(English version is down below)&lt;/p&gt;
&lt;p&gt;源Github项目地址：&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message"&gt;https://github.com/HollowMan6/Wechat-Timed-Message&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
好用记得收藏(右上角&lt;strong&gt;加星★Star&lt;/strong&gt;)哦!&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/HollowMan6/Wechat-Timed-MessageWechat-Timed-Message.py"&gt;微信消息推送脚本&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message.github/workflows"&gt;工作流存放文件夹&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;支持&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95"&gt;Fork本仓库直接使用工作流(推荐)&lt;/a&gt;，&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message#gitlab"&gt;GitLab使用Pipeline&lt;/a&gt;，&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message#%E8%87%AA%E8%A1%8C%E9%85%8D%E7%BD%AE%E5%B7%A5%E4%BD%9C%E6%B5%81"&gt;自行创建仓库使用工作流&lt;/a&gt;，&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message#crontab"&gt;CronTab/Python后台定时调度运行&lt;/a&gt;，&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message#docker"&gt;Docker运行&lt;/a&gt;，&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message#kubernetes"&gt;Kubernetes直接运行&lt;/a&gt;，&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message#helm"&gt;使用Helm包管理在Kubernetes运行&lt;/a&gt;，&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message#heroku"&gt;Heroku部署运行&lt;/a&gt;等。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://hub.docker.com/r/hollowman6/send-message-to-wechat" rel="nofollow"&gt;Docker镜像&lt;/a&gt;支持在&lt;code&gt;amd64&lt;/code&gt;、&lt;code&gt;arm64&lt;/code&gt;、&lt;code&gt;arm32v7&lt;/code&gt;、&lt;code&gt;arm32v6&lt;/code&gt;、&lt;code&gt;ppc64le&lt;/code&gt;、&lt;code&gt;s390x&lt;/code&gt;、&lt;code&gt;i386&lt;/code&gt;、&lt;code&gt;mips64le&lt;/code&gt;多架构(包括大型机、普通PC机以及树莓派等开发板)运行。&lt;/p&gt;
&lt;h2&gt;
使用方法&lt;/h2&gt;
&lt;p&gt;你需要fork本仓库，之后在你fork的仓库中创建相关Actions Secret并进行相关设置(按下图所示点击1，2，3的次序，即可进入新建Actions secrets的界面):&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/secrets.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VRywhW5J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/secrets.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;你可以从以下三个推送平台中任选一个或多个来接受推送的消息：&lt;/p&gt;
&lt;h3&gt;
PushPlus(推荐)&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.pushplus.plus/login" rel="nofollow"&gt;登录PushPlus&lt;/a&gt;，然后在pushplus网站中找到您的token，创建一个Name为&lt;code&gt;PPTOKEN&lt;/code&gt;，value为您的token值的Actions secret，就可以进行一对一推送信息。&lt;/p&gt;
&lt;p&gt;如果需要对多个账号推送信息，即一对多推送，还需要另外新建一个群组，记下群组编码，然后创建一个Name为&lt;code&gt;PPTOPIC&lt;/code&gt;，value为您的群组编码的Actions secret。&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/c1.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M8fB9qM8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/c1.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
企业微信推送&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;首先注册&lt;a href="https://work.weixin.qq.com/wework_admin/loginpage_wx" rel="nofollow"&gt;企业微信&lt;/a&gt;。&lt;/li&gt;
&lt;li&gt;注册成功后，获取企业id，创建一个Name为&lt;code&gt;CORPID&lt;/code&gt;，value为您的企业id值的Actions secret。
&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/wecomid.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fuog2ugT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/wecomid.png" alt=""&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;选择&lt;code&gt;应用管理&lt;/code&gt; → &lt;code&gt;应用&lt;/code&gt; → &lt;code&gt;创建应用&lt;/code&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/wecom_create_apps.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PA4BOIc4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/wecom_create_apps.png" alt=""&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;自己创建完成后获取Secret和AgentId，创建分别Name为&lt;code&gt;CORPSECRET&lt;/code&gt;和&lt;code&gt;AGENTID&lt;/code&gt;，value为这些值的Actions secret。
&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/wecom_apps.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ygDpAe8L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/wecom_apps.png" alt=""&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;进入&lt;code&gt;我的企业&lt;/code&gt; → &lt;code&gt;微信插件&lt;/code&gt;，拉到下边扫描二维码，关注以后即可收到推送的消息。
&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/wecom_wechat.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WR19DiVv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/wecom_wechat.png" alt=""&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;效果示意
&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/wecom.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xs5w4gMK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/wecom.jpg" alt=""&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/wecom_content.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mDdAIhMp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/wecom_content.jpg" alt=""&gt;&lt;/a&gt;
&lt;a href="https://open.work.weixin.qq.com/wwopen/mpnews?mixuin=pHhNDQAABwCobsHiAAAUAA&amp;amp;mfid=WW0324-8tTQjQAABwBCZs6oZBo1yA3mwAO57&amp;amp;idx=0&amp;amp;sn=4f42d0909560e8b42dd756d0ac1b04b6" rel="nofollow"&gt;示例内容&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
Server酱&lt;/h3&gt;
&lt;p&gt;如果要使用&lt;a href="https://sct.ftqq.com/" rel="nofollow"&gt;Server酱&lt;/a&gt;，请创建一个/修改Name为&lt;code&gt;SERVERCHANSCKEY&lt;/code&gt;，value为&lt;a href="https://sct.ftqq.com/sendkey" rel="nofollow"&gt;你的SendKey值&lt;/a&gt;的Actions secret。&lt;/p&gt;

&lt;p&gt;上述配置成功后，配置工作流文件，以&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message.github/workflows/1.yml"&gt;工作流1.yml&lt;/a&gt;为模板，创建你自己的工作流或者在提供的工作流上进行修改。你可以任意更改name为无空格的英文字母和数字组合的字符串，cron为你想要发送消息的指定时间(你可以使用&lt;a href="https://crontab.guru/" rel="nofollow"&gt;crontab guru&lt;/a&gt;进行cron表达式的调试，所有时间均为UTC时间，请进行时区换算)(因为Github方的原因，预定运行时间可能会有半小时左右的延迟)。然后创建一个或者两个Actions secrets，一个必须创建，其name为&lt;code&gt;TITLE[name]&lt;/code&gt;（请将这里的&lt;code&gt;[name]&lt;/code&gt;修改为workflow的name），value为要发送消息的标题，例如在提供的工作流中，这里的name为&lt;code&gt;TITLE1&lt;/code&gt;；另一个为可选的，其name为&lt;code&gt;MSG[name]&lt;/code&gt;，同理进行相应的替换，value为要发送消息的标题。&lt;/p&gt;
&lt;p&gt;随后，按下图所示点击1，2，3，4的次序，你可以手动触发工作流的执行来进行测试。&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/workflow.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dxUPGekG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/workflow.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;点开任意一个运行记录，依次点开下图所示1，2，你可以看到运行记录。&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/run.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--El-3tzBc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/run.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;如果某次因为某些因素工作流运行失败，GitHub会自动发邮件提醒工作流运行失败。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;新&lt;/strong&gt;：增加可选的遇到发送消息失败的情况，自动重启工作流，并等待一段时间后再次发送消息。如果你需要这个功能，则请创建一个Personal Access Token, &lt;a href="https://docs.github.com/cn/github/authenticating-to-github/creating-a-personal-access-token#creating-a-token"&gt;获取教程&lt;/a&gt;(第7步令牌的作用域权限你只需要选中workflow这一栏即可)。然后创建一个Name为&lt;code&gt;GPATOKEN&lt;/code&gt;，value为你的令牌值的Actions Secret。&lt;/p&gt;
&lt;p&gt;默认再次发送消息等待时间为30分钟，如果你有需要可以修改你的fork仓库对应的&lt;a href="https://github.com/HollowMan6/Wechat-Timed-Message/blob/main/.github/workflows/1.yml#L43"&gt;这里&lt;/a&gt;的&lt;code&gt;30m&lt;/code&gt;替换为你想要的数值，这里的时间遵循Linux sleep 函数对应时间语法：一个数字后接 &lt;code&gt;s&lt;/code&gt; 对应秒, &lt;code&gt;m&lt;/code&gt; 对应分钟等。&lt;/p&gt;
&lt;p&gt;如果是因为本仓库程序本身因为失效而导致的报错，你可以取消正在运行中的工作流从而终止这一循环。&lt;/p&gt;
&lt;h2&gt;
GitLab&lt;/h2&gt;
&lt;p&gt;GitLab仓库地址：&lt;a href="https://gitlab.com/HollowMan6/Wechat-Timed-Message" rel="nofollow"&gt;https://gitlab.com/HollowMan6/Wechat-Timed-Message&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;你还可以使用GitLab的Pipeline来进行消息推送：&lt;/p&gt;
&lt;p&gt;同理，fork完GitLab仓库到你的名下后，创建Variables（类似于GitHub Actions Secrets）：&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/gitlab_create_variable.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a2oaHA6d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/gitlab_create_variable.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/gitlab_create_variable_result.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ASk2ukNE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/gitlab_create_variable_result.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;同理，你还可以创建一个Pipeline triggers(类似于Github Access Token)并加入到Variables中来启用自动打开失败再次消息推送：&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Messageimg/gitlab_ci_triggers.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kLNYrQ8t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Messageimg/gitlab_ci_triggers.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;默认再次消息推送等待时间为30分钟，如果你有需要可以修改你的fork仓库对应的…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HollowMan6/Wechat-Timed-Message"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/aks/quickstart-helm#run-your-helm-chart"&gt;https://docs.microsoft.com/en-us/azure/aks/quickstart-helm#run-your-helm-chart&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azuretrialhack</category>
    </item>
    <item>
      <title>openEuler 20.03 LTS SP3 Kickstart Automatic Installation on VMware Workstation</title>
      <dc:creator>Hollow Man</dc:creator>
      <pubDate>Thu, 17 Feb 2022 13:59:07 +0000</pubDate>
      <link>https://dev.to/hollowman6/openeuler-2003-lts-sp3-kickstart-automatic-installation-on-vmware-workstation-m0c</link>
      <guid>https://dev.to/hollowman6/openeuler-2003-lts-sp3-kickstart-automatic-installation-on-vmware-workstation-m0c</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As &lt;a href="https://www.openeuler.org/en/" rel="noopener noreferrer"&gt;openEuler&lt;/a&gt; also uses &lt;a href="https://en.wikipedia.org/wiki/Anaconda_(installer)" rel="noopener noreferrer"&gt;Redhat Anaconda&lt;/a&gt; as its OS installer, we can &lt;a href="https://docs.openeuler.org/en/docs/20.03_LTS_SP3/docs/Installation/using-kickstart-for-automatic-installation.html" rel="noopener noreferrer"&gt;use Kickstart for Automatic Installation&lt;/a&gt;. However, the guides provided in the previous documentation officially are not straightforward enough for Linux newbies who tend to use virtual machines for installation. So in this blog, I'm going to show you how to perform openEuler 20.03 LTS SP3 Kickstart Automatic Installation on VMware Workstation with only a single ISO file referring to the &lt;a href="https://docs.centos.org/en-US/centos/install-guide/Kickstart2/" rel="noopener noreferrer"&gt;CentOS Kickstart Installations Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the Kickstart file
&lt;/h3&gt;

&lt;p&gt;Copy the following code into a file named &lt;code&gt;ks.cfg&lt;/code&gt; at somewhere on your computer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="c"&gt;#version=DEVEL
# Use graphical install
&lt;/span&gt;&lt;span class="n"&gt;graphical&lt;/span&gt;


%&lt;span class="n"&gt;packages&lt;/span&gt;
@^&lt;span class="n"&gt;minimal&lt;/span&gt;-&lt;span class="n"&gt;environment&lt;/span&gt;
@&lt;span class="n"&gt;standard&lt;/span&gt;

%&lt;span class="n"&gt;end&lt;/span&gt;

&lt;span class="c"&gt;# Keyboard layouts
&lt;/span&gt;&lt;span class="n"&gt;keyboard&lt;/span&gt; --&lt;span class="n"&gt;xlayouts&lt;/span&gt;=&lt;span class="s1"&gt;'cn'&lt;/span&gt;
&lt;span class="c"&gt;# System language
&lt;/span&gt;&lt;span class="n"&gt;lang&lt;/span&gt; &lt;span class="n"&gt;zh_CN&lt;/span&gt;.&lt;span class="n"&gt;UTF&lt;/span&gt;-&lt;span class="m"&gt;8&lt;/span&gt;

&lt;span class="c"&gt;# Network information
&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;  --&lt;span class="n"&gt;bootproto&lt;/span&gt;=&lt;span class="n"&gt;dhcp&lt;/span&gt; --&lt;span class="n"&gt;device&lt;/span&gt;=&lt;span class="n"&gt;ens160&lt;/span&gt; --&lt;span class="n"&gt;onboot&lt;/span&gt;=&lt;span class="n"&gt;off&lt;/span&gt; --&lt;span class="n"&gt;ipv6&lt;/span&gt;=&lt;span class="n"&gt;auto&lt;/span&gt; --&lt;span class="n"&gt;activate&lt;/span&gt;
&lt;span class="n"&gt;network&lt;/span&gt;  --&lt;span class="n"&gt;hostname&lt;/span&gt;=&lt;span class="n"&gt;localhost&lt;/span&gt;.&lt;span class="n"&gt;localdomain&lt;/span&gt;

&lt;span class="c"&gt;# Use CDROM installation media
&lt;/span&gt;&lt;span class="n"&gt;cdrom&lt;/span&gt;

&lt;span class="c"&gt;# Run the Setup Agent on first boot
&lt;/span&gt;&lt;span class="n"&gt;firstboot&lt;/span&gt; --&lt;span class="n"&gt;enable&lt;/span&gt;
&lt;span class="c"&gt;# System services
&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt; --&lt;span class="n"&gt;enabled&lt;/span&gt;=&lt;span class="s2"&gt;"chronyd"&lt;/span&gt;

&lt;span class="n"&gt;ignoredisk&lt;/span&gt; --&lt;span class="n"&gt;only&lt;/span&gt;-&lt;span class="n"&gt;use&lt;/span&gt;=&lt;span class="n"&gt;nvme0n1&lt;/span&gt;
&lt;span class="n"&gt;autopart&lt;/span&gt;
&lt;span class="c"&gt;# Partition clearing information
&lt;/span&gt;&lt;span class="n"&gt;clearpart&lt;/span&gt; --&lt;span class="n"&gt;none&lt;/span&gt; --&lt;span class="n"&gt;initlabel&lt;/span&gt;

&lt;span class="c"&gt;# System timezone
&lt;/span&gt;&lt;span class="n"&gt;timezone&lt;/span&gt; &lt;span class="n"&gt;Asia&lt;/span&gt;/&lt;span class="n"&gt;Shanghai&lt;/span&gt; --&lt;span class="n"&gt;utc&lt;/span&gt;

&lt;span class="c"&gt;# Root password
&lt;/span&gt;&lt;span class="n"&gt;rootpw&lt;/span&gt; &lt;span class="n"&gt;openeuler&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt; --&lt;span class="n"&gt;groups&lt;/span&gt;=&lt;span class="n"&gt;wheel&lt;/span&gt; --&lt;span class="n"&gt;name&lt;/span&gt;=&lt;span class="n"&gt;openeuler&lt;/span&gt; --&lt;span class="n"&gt;password&lt;/span&gt;=&lt;span class="n"&gt;openeuler&lt;/span&gt; --&lt;span class="n"&gt;gecos&lt;/span&gt;=&lt;span class="s2"&gt;"openEuler"&lt;/span&gt;

%&lt;span class="n"&gt;addon&lt;/span&gt; &lt;span class="n"&gt;com_redhat_kdump&lt;/span&gt; --&lt;span class="n"&gt;disable&lt;/span&gt; --&lt;span class="n"&gt;reserve&lt;/span&gt;-&lt;span class="n"&gt;mb&lt;/span&gt;=&lt;span class="s1"&gt;'128'&lt;/span&gt;

%&lt;span class="n"&gt;end&lt;/span&gt;

%&lt;span class="n"&gt;anaconda&lt;/span&gt;
&lt;span class="n"&gt;pwpolicy&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; --&lt;span class="n"&gt;minlen&lt;/span&gt;=&lt;span class="m"&gt;8&lt;/span&gt; --&lt;span class="n"&gt;minquality&lt;/span&gt;=&lt;span class="m"&gt;1&lt;/span&gt; --&lt;span class="n"&gt;strict&lt;/span&gt; --&lt;span class="n"&gt;nochanges&lt;/span&gt; --&lt;span class="n"&gt;notempty&lt;/span&gt;
&lt;span class="n"&gt;pwpolicy&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; --&lt;span class="n"&gt;minlen&lt;/span&gt;=&lt;span class="m"&gt;8&lt;/span&gt; --&lt;span class="n"&gt;minquality&lt;/span&gt;=&lt;span class="m"&gt;1&lt;/span&gt; --&lt;span class="n"&gt;strict&lt;/span&gt; --&lt;span class="n"&gt;nochanges&lt;/span&gt; --&lt;span class="n"&gt;emptyok&lt;/span&gt;
&lt;span class="n"&gt;pwpolicy&lt;/span&gt; &lt;span class="n"&gt;luks&lt;/span&gt; --&lt;span class="n"&gt;minlen&lt;/span&gt;=&lt;span class="m"&gt;8&lt;/span&gt; --&lt;span class="n"&gt;minquality&lt;/span&gt;=&lt;span class="m"&gt;1&lt;/span&gt; --&lt;span class="n"&gt;strict&lt;/span&gt; --&lt;span class="n"&gt;nochanges&lt;/span&gt; --&lt;span class="n"&gt;notempty&lt;/span&gt;
%&lt;span class="n"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above Kickstart file will set Chinese as the default language, and set the root password to &lt;code&gt;openeuler&lt;/code&gt;, with an additional account name and password both &lt;code&gt;openeuler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want to create your own Kickstart file, you can firstly perform a manual installation you would like, after successfully installing and logging into the system, get the generated Kickstart file that corresponds to the manual installation just performed at &lt;code&gt;/root/anaconda-ks.cfg&lt;/code&gt;, rename it to &lt;code&gt;ks.cfg&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generate the ISO file
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If you are on Linux, run &lt;a href="https://linux.die.net/man/8/mkisofs" rel="noopener noreferrer"&gt;mkisofs&lt;/a&gt; for ISO generation:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &amp;lt;the folder where you store your ks.cfg&amp;gt;
mkisofs &lt;span class="nt"&gt;-JR&lt;/span&gt; &lt;span class="nt"&gt;-V&lt;/span&gt; OEMDRV &lt;span class="nt"&gt;-o&lt;/span&gt; auto-installation.iso ks.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F02%2F5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F02%2F5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you are on Windows, you can use &lt;a href="https://www.ultraiso.com/download.html" rel="noopener noreferrer"&gt;UltraISO&lt;/a&gt; for ISO generation:&lt;/li&gt;
&lt;li&gt;open UltraISO, click on the &lt;code&gt;New&lt;/code&gt; button, rename the disk into &lt;code&gt;OEMDRV&lt;/code&gt;.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F02%2F3.png"&gt;
&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;F3&lt;/code&gt; to add file &lt;code&gt;ks.cfg&lt;/code&gt; into the ISO, then click on the &lt;code&gt;Save&lt;/code&gt; button to save the ISO file as &lt;code&gt;auto-installation.iso&lt;/code&gt;.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F02%2F4.png"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Configure the Virtual Machine
&lt;/h3&gt;

&lt;p&gt;Please first create the virtual machine on VMware Workstation for openEuler 20.03 LTS SP3. If you don't know how to do this, please refer to the VMware Workstation documentation or related blogs as there're already many tutorials that exist.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the Virtual Machine's tab, click on the &lt;code&gt;Edit virtual machine settings&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On the prompted &lt;code&gt;Virtual Machine Settings&lt;/code&gt; window, click on the &lt;code&gt;Add...&lt;/code&gt; button.&lt;/li&gt;
&lt;li&gt;On the prompted &lt;code&gt;Add Hardware Wizard&lt;/code&gt; dialogue, choose &lt;code&gt;CD/DVD Drive&lt;/code&gt;, click on the &lt;code&gt;Finish&lt;/code&gt; button.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F02%2F1.png"&gt;
&lt;/li&gt;
&lt;li&gt;Then for the newly added CD/DVD Device, choose &lt;code&gt;Use ISO image file:&lt;/code&gt;, and click on the &lt;code&gt;Browse...&lt;/code&gt; button to select the ISO file &lt;code&gt;auto-installation.iso&lt;/code&gt; just created in the last step, finally click on the &lt;code&gt;OK&lt;/code&gt; button.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F02%2F2.png"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At last, start your virtual machine and enjoy Kickstart automatic installation!&lt;/p&gt;

</description>
      <category>linux</category>
    </item>
    <item>
      <title>mdbook-pdf: A mdBook backend for generating PDF files</title>
      <dc:creator>Hollow Man</dc:creator>
      <pubDate>Sun, 30 Jan 2022 07:09:48 +0000</pubDate>
      <link>https://dev.to/hollowman6/mdbook-pdf-a-mdbook-backend-for-generating-pdf-files-4m6p</link>
      <guid>https://dev.to/hollowman6/mdbook-pdf-a-mdbook-backend-for-generating-pdf-files-4m6p</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/rust-lang/mdBook" rel="noopener noreferrer"&gt;mdBook&lt;/a&gt; allows you to create book from markdown files. It's pretty much alike &lt;a href="https://www.gitbook.com/" rel="noopener noreferrer"&gt;Gitbook&lt;/a&gt; but implemented in Rust. However, unlike Gitbook that supports using calibre for generating PDF, for a long time, mdBook &lt;a href="https://github.com/rust-lang/mdBook/issues/88" rel="noopener noreferrer"&gt;doesn't support generating PDF files natively&lt;/a&gt;, and supporting that is also not in their roadmap. Existing plugins (backends) such as &lt;a href="https://github.com/lbeckman314/mdbook-latex" rel="noopener noreferrer"&gt;mdbook-latex&lt;/a&gt; that utilize &lt;a href="https://github.com/tectonic-typesetting/tectonic" rel="noopener noreferrer"&gt;Tectonic&lt;/a&gt; as well as pandoc solutions will generate a PDF page that doesn't unify with the existing mdBook generated HTML version. Considering these facts, I created a mdBook backend named &lt;a href="https://crates.io/crates/mdbook-pdf" rel="noopener noreferrer"&gt;mdbook-pdf&lt;/a&gt; for generating PDF based on &lt;a href="https://github.com/atroche/rust-headless-chrome" rel="noopener noreferrer"&gt;headless chrome&lt;/a&gt; and &lt;a href="https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF" rel="noopener noreferrer"&gt;Chrome DevTools Protocol Page.printToPDF&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;mdbook-pdf depends on Google Chrome / Microsoft Edge / Chromium. The generated page are pretty much alike the one you manually print to PDF in your browser by opening &lt;code&gt;print.html&lt;/code&gt; or executing &lt;code&gt;google-chrome-stable --headless --print-to-pdf=output.pdf file:///path/to/print.html&lt;/code&gt;, but with customization of PDF paper orientation, scale of the webpage rendering, paper width and height, page margins, generated PDF page ranges, whether to display header and footer as well as customize their formats, and more, as well as automation. It supports all the platform where Google Chrome / Microsoft Edge / Chromium would work. You can check samples of the generated PDF files in the Artifacts &lt;a href="https://github.com/HollowMan6/mdbook-pdf/actions/runs/1766229211" rel="noopener noreferrer"&gt;here&lt;/a&gt; (The Rust book collections generated in x86_64 Windows, macOS as well as Linux). &lt;/p&gt;

&lt;h2&gt;
  
  
  Installation &amp;amp; Usage
&lt;/h2&gt;

&lt;p&gt;Since it's a plugin (backend) for &lt;a href="https://github.com/rust-lang/mdBook" rel="noopener noreferrer"&gt;mdBook&lt;/a&gt;, first of all you should ensure that &lt;code&gt;mdbook&lt;/code&gt; is available.&lt;/p&gt;

&lt;p&gt;If your machine's architecture is &lt;code&gt;x86_64&lt;/code&gt;, or you are using Linux for &lt;code&gt;ARM64&lt;/code&gt;, check the successful &lt;a href="https://github.com/HollowMan6/mdbook-pdf/actions/workflows/build.yml?query=is%3Asuccess" rel="noopener noreferrer"&gt;build GitHub Actions workflows&lt;/a&gt;, click into the latest one, and then you can get a binary from the Artifacts (including &lt;code&gt;Windows&lt;/code&gt;, &lt;code&gt;Linux&lt;/code&gt;, &lt;code&gt;macOS&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Otherwise, make sure the &lt;a href="https://www.rust-lang.org/tools/install" rel="noopener noreferrer"&gt;rust compiling environment&lt;/a&gt; is available, execute &lt;code&gt;cargo install mdbook-pdf&lt;/code&gt; to compile and install.&lt;/p&gt;

&lt;p&gt;If you want to compile the latest version, make sure the Rust build environment is available (&lt;code&gt;cargo build&lt;/code&gt;).&lt;br&gt;
Then run &lt;code&gt;git clone https://github.com/HollowMan6/mdbook-pdf.git&lt;/code&gt;, in the cloned folder, run &lt;code&gt;cargo build --release&lt;/code&gt; , get the executable in &lt;code&gt;target/release/&lt;/code&gt;, and put it in PATH.&lt;/p&gt;

&lt;p&gt;For running, have Google Chrome / Chromium / Microsoft Edge available (installed at the default location, in PATH or binary location configured) as currently, automatically downloading Chromium binary &lt;a href="https://github.com/atroche/rust-headless-chrome/issues/286" rel="noopener noreferrer"&gt;isn't available&lt;/a&gt; (will update once upstream fixes such support).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On Windows 10 and above, the program can generate PDF normally without installing any additional software, because Microsoft Edge is the browser provided with Windows system. Of course, considering the support for the older versions of Windows without Edge, you can install Google Chrome on your computer.&lt;/li&gt;
&lt;li&gt;In MacOS, you need to install &lt;a href="https://www.google.com/chrome/" rel="noopener noreferrer"&gt;Google Chrome&lt;/a&gt; / &lt;a href="https://www.microsoft.com/en-us/edge" rel="noopener noreferrer"&gt;Microsoft Edge&lt;/a&gt; or Chromium.&lt;/li&gt;
&lt;li&gt;In Linux, you can choose to install any of the Google Chrome / Chromium / Microsoft Edge browsers. It is recommended to install Chromium. The name of this software package in your Linux distribution is commonly &lt;code&gt;chromium&lt;/code&gt; or &lt;code&gt;chromium-browser&lt;/code&gt; (Note: for Ubuntu later than 18.04, you have to install &lt;code&gt;chromium-browser&lt;/code&gt; through &lt;code&gt;snap&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make sure the following exists in your &lt;code&gt;book.toml&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;

&lt;span class="nn"&gt;[output.html]&lt;/span&gt;

&lt;span class="nn"&gt;[output.pdf]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And also &lt;code&gt;[output.html.print]&lt;/code&gt; is not disabled (it should be enabled by default, so don't worry if the following lines doesn't occur in you &lt;code&gt;book.toml&lt;/code&gt;).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;

&lt;span class="nn"&gt;[output.html.print]&lt;/span&gt;
&lt;span class="py"&gt;enable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A simplest &lt;code&gt;book.toml&lt;/code&gt; is as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;

&lt;span class="nn"&gt;[book]&lt;/span&gt;
&lt;span class="py"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"An Example"&lt;/span&gt;

&lt;span class="nn"&gt;[output.html]&lt;/span&gt;

&lt;span class="nn"&gt;[output.pdf]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally you can build your book and get the PDF file with &lt;code&gt;mdbook build&lt;/code&gt; command, your PDF file will be available at &lt;code&gt;book/pdf/output.pdf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2Fimage.png" alt="An example for the output of the building progress"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;Check &lt;a href="https://github.com/HollowMan6/mdbook-pdf/blob/v0.1.0/test_doc/book.toml#L10-L33" rel="noopener noreferrer"&gt;book.toml&lt;/a&gt; and comments for details for the available configurations of &lt;code&gt;[output.pdf]&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;This project relies on &lt;a href="https://github.com/atroche/rust-headless-chrome" rel="noopener noreferrer"&gt;headless_chrome&lt;/a&gt;. Because the new version has not been released, and the default timeout is not friendly to PDF generation, I use my &lt;a href="https://github.com/HollowMan6/rust-headless-chrome" rel="noopener noreferrer"&gt;Fork version&lt;/a&gt; to publish &lt;a href="https://crates.io/crates/mdbook-pdf-headless_chrome" rel="noopener noreferrer"&gt;mdbook-pdf-headless_chrome&lt;/a&gt; for expanding the relevant timeout to 300 seconds as a submodule of this project, thus enabling the project to be published on &lt;a href="https://crates.io/" rel="noopener noreferrer"&gt;Crates.io&lt;/a&gt; as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some Notes and Thoughts
&lt;/h2&gt;

&lt;p&gt;mdBook supports adding alternative backend. When the &lt;code&gt;mdbook build&lt;/code&gt; command is invoked, if the &lt;code&gt;book.toml&lt;/code&gt; in the book folder has an &lt;code&gt;[output.pdf]&lt;/code&gt; item in addition to the default &lt;code&gt;[output.html]&lt;/code&gt; for generating the html web page, &lt;code&gt;mdbook-pdf&lt;/code&gt; will be called, and the relevant book information and parameter configuration in JSON are passed to the standard input of the program. Relevant mdBook documentation can be found &lt;a href="https://rust-lang.github.io/mdBook/for_developers/backends.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F1.drawio.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F1.drawio.png" alt="Mechanism behind mdbook-pdf"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/Headless_browser" rel="noopener noreferrer"&gt;headless browser&lt;/a&gt; means that all the operations will be in the background without a graphical interface.&lt;/p&gt;

&lt;p&gt;Before decided to use &lt;a href="https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF" rel="noopener noreferrer"&gt;Chrome DevTools Protocol Page.printToPDF&lt;/a&gt;, I also tried &lt;a href="https://wkhtmltopdf.org/" rel="noopener noreferrer"&gt;wkhtmltopdf&lt;/a&gt; which is based on QT4 Webkit. Hovewer, wkhtmltopdf doesn't seem to support &lt;a href="https://www.tutorialspoint.com/css/css_printing.htm" rel="noopener noreferrer"&gt;CSS Printing @media Rule&lt;/a&gt;, which will make some extra components visible and printed in the PDF.&lt;/p&gt;

&lt;p&gt;I've also tried &lt;a href="https://github.com/HollowMan6/mdbook-pdf/tree/webdriver-python" rel="noopener noreferrer"&gt;directly making HTTP calls to the WebDriver in python&lt;/a&gt; based on &lt;a href="https://w3c.github.io/webdriver/#print-page" rel="noopener noreferrer"&gt;W3C WebDriver Protocol Print Page&lt;/a&gt;, as well as using selenium for calling Chrome DevTools Protocol Page.printToPDF &lt;a href="https://github.com/HollowMan6/mdbook-pdf/tree/chrome-devtools-python" rel="noopener noreferrer"&gt;in Python&lt;/a&gt;. All those methods are not robust for large pages with the errors as follows for just the same reason for the original upstream &lt;a href="https://github.com/atroche/rust-headless-chrome" rel="noopener noreferrer"&gt;headless_chrome&lt;/a&gt;: the default timeout is 10 seconds, which is not friendly to large page PDF generation.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;timeout&lt;/span&gt;: Timed out receiving message from renderer: 10.000


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

selenium.common.exceptions.WebDriverException: Message: unknown error: session deleted because of page crash
from unknown error: cannot determine loading status
from tab crashed


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;At present, I have tested that Firefox does not support using &lt;a href="https://github.com/atroche/rust-headless-chrome" rel="noopener noreferrer"&gt;headless_chrome&lt;/a&gt; for PDF generation, and the Safari browser even does not support the &lt;a href="https://w3c.github.io/webdriver/#print-page" rel="noopener noreferrer"&gt;W3C WebDriver Protocol Print Page&lt;/a&gt;, let alone Chrome DevTools Protocol.&lt;/p&gt;

&lt;p&gt;I've noticed that for some book, by using this backend, when click on some links that link inside the book, a html page that points to the original generated HTML storing path of the book will be opened, just as the &lt;a href="https://github.com/rust-lang/mdBook/issues/88#issuecomment-962613257" rel="noopener noreferrer"&gt;issue mentioned here&lt;/a&gt;. I guess for those "internal" links inside the book, work should be done in the mdbook side for &lt;code&gt;print.html&lt;/code&gt; &lt;a href="https://blog.hubspot.com/marketing/jump-link-same-page" rel="noopener noreferrer"&gt;referring here&lt;/a&gt; so that all the links linked "internally" would jump inside the generated &lt;code&gt;print.html&lt;/code&gt;, as all the contents should already be on the &lt;code&gt;print.html&lt;/code&gt;, there shouldn't be any hyperlinks that jump to other html files in the book. By resolving in this way, the generated PDF would also jump internally instead of opening a browser that won't connect to anything. I have already created &lt;a href="https://github.com/rust-lang/mdBook/pull/1738" rel="noopener noreferrer"&gt;a PR for this&lt;/a&gt;, hope it will get merged soon.&lt;/p&gt;

&lt;p&gt;In addition, as I found that special characters such as &lt;code&gt;:&lt;/code&gt; are very likely to appear in the title of the book, which will cause the generation of the related PDF file to fail, so the file name does not use the form of &lt;code&gt;&amp;lt;book name&amp;gt;.pdf&lt;/code&gt; but &lt;code&gt;output.pdf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Hope you enjoy it.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>markdown</category>
      <category>books</category>
    </item>
    <item>
      <title>Deploy a Kubernetes Cluster based on Calico and openSUSE Kubic</title>
      <dc:creator>Hollow Man</dc:creator>
      <pubDate>Thu, 27 Jan 2022 16:37:17 +0000</pubDate>
      <link>https://dev.to/hollowman6/deploy-a-kubernetes-cluster-based-on-calico-and-opensuse-kubic-31d0</link>
      <guid>https://dev.to/hollowman6/deploy-a-kubernetes-cluster-based-on-calico-and-opensuse-kubic-31d0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://kubic.opensuse.org/" rel="noopener noreferrer"&gt;openSUSE Kubic&lt;/a&gt; is a certified Kubernetes Distribution based on openSUSE MicroOS. &lt;a href="https://www.tigera.io/project-calico/" rel="noopener noreferrer"&gt;Calico&lt;/a&gt; is an open-source project that can be used by Kubernetes to deploy a pod network to the cluster. In this blog, I will show you how to deploy a Kubernetes Cluster based on Calico and openSUSE Kubic by a Virtual Machine. We are going to deploy a cluster that has a master and a worker.&lt;/p&gt;

&lt;p&gt;I was intended to use &lt;a href="https://www.virtualbox.org/" rel="noopener noreferrer"&gt;Oracle VM VirtualBox&lt;/a&gt;. However, it turned out that on my machine, when I tried to run &lt;code&gt;kubeadm&lt;/code&gt; at openSUSE Kubic in VirtualBox, it always stuck at &lt;code&gt;watchdog: BUG: soft lockup - CPU#? stuck for xxs!&lt;/code&gt; with CPU usage around 100%. As a result, I switched to &lt;a href="https://www.vmware.com/products/workstation-pro/workstation-pro-evaluation.html" rel="noopener noreferrer"&gt;VMware Workstation Pro&lt;/a&gt; and the issue got solved. Guess it's caused by some bugs of VirtualBox.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the Virtual Machine and Install openSUSE Kubic
&lt;/h3&gt;

&lt;p&gt;Here I won't explain how to do these things but share some important things to note, just refer to their documents if you don't know or have any questions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Here is my configuration for the Virtual Machine. Recommend that your host machine has a memory that is larger than 8GB so that more than 3GB of memory can be assigned to the Virtual Machine for it to run smoothly. In order for the Virtual Machines to be connected to each other, and also connect to the Internet, you can set the Network Adapter to be &lt;code&gt;Bridged (Automatic)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For openSUSE Kubic Installation, remember to choose &lt;code&gt;kubeadm Node&lt;/code&gt; when it comes to System Role, as it will deploy a &lt;a href="https://www.weave.works/oss/net/" rel="noopener noreferrer"&gt;Weave&lt;/a&gt; pod network cluster instead of Calico if you choose to use Kubic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I suggest that you can install the openSUSE Kubic in one Virtual Machine, later after successful installation, clone that Virtual Machine, assign one as master and another worker. Remember to do a full clone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring the Master
&lt;/h3&gt;

&lt;p&gt;When you boot into the master Virtual Machine, you can see your IP address in the notification part. In my case, it's &lt;code&gt;192.168.1.14&lt;/code&gt;. Take note of that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F4.png"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;For the convenience of copy and paste commands, we can use SSH to log into the system. To configure that, first, log into the system with root account. Second, execute &lt;code&gt;vi /etc/ssh/sshd_config.d/10-enable-root-password.conf&lt;/code&gt;, type &lt;code&gt;i&lt;/code&gt; to insert, write the following into the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;PasswordAuthentication&lt;/span&gt; &lt;span class="n"&gt;yes&lt;/span&gt;
&lt;span class="n"&gt;PermitRootLogin&lt;/span&gt; &lt;span class="n"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will enable SSH root password login, although it's not recommended if you are in production. When editing is finished, press &lt;code&gt;[ESC]&lt;/code&gt; then type &lt;code&gt;:wq&lt;/code&gt; to save and exit.&lt;/p&gt;




&lt;h4&gt;
  
  
  Kubeadm Init
&lt;/h4&gt;

&lt;p&gt;Run &lt;code&gt;kubeadm config images pull&lt;/code&gt; to pull the container images required for Kubernetes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also specify the &lt;code&gt;--image-repository&lt;/code&gt; if, in your location, &lt;code&gt;registry.opensuse.org&lt;/code&gt; downloading speed is too slow. In my case (in China) I'll use Aliyun to speed up: &lt;code&gt;kubeadm config images pull --image-repository registry.aliyuncs.com/google_containers&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F6.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then run &lt;code&gt;kubeadm init --apiserver-advertise-address=&amp;lt;Your Master IP Address&amp;gt; --pod-network-cidr=192.168.0.0/16&lt;/code&gt;, replace &lt;code&gt;&amp;lt;Your Master IP Address&amp;gt;&lt;/code&gt; with the IP address you just noted. If you specified the &lt;code&gt;--image-repository&lt;/code&gt; in the last step, also append that to this command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F7.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F8.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait for it to finish, remember to take notes of the worker nodes joining command.&lt;/p&gt;

&lt;p&gt;Execute &lt;code&gt;export KUBECONFIG=/etc/kubernetes/admin.conf&lt;/code&gt; in your shell for the kubectl to work.&lt;/p&gt;

&lt;h4&gt;
  
  
  Deploy Calico
&lt;/h4&gt;

&lt;p&gt;Get the latest copy of the calico configuration yaml file by &lt;code&gt;curl -O https://docs.projectcalico.org/manifests/calico.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Change the path to install the FlexVolume driver by &lt;code&gt;sed -i 's#/usr/libexec/kubernetes/kubelet-plugins/volume/exec#/var/lib/kubelet/volume-plugin#g' calico.yaml&lt;/code&gt; as in Transactional (Atomic) systems &lt;code&gt;/usr/libexec/kubernetes&lt;/code&gt; &lt;a href="https://github.com/projectcalico/calico/issues/2712#issuecomment-510044213" rel="noopener noreferrer"&gt;is read-only&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, apply the yaml file by &lt;code&gt;kubectl apply -f calico.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F9.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait for all the pods to be available.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;watch kubectl get pods &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F10.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can check the Events of the pod to get the error messages if you are waiting too much time on a specific pod: &lt;code&gt;kubectl describe pods -n kube-system &amp;lt;Pod Name&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring the Worker
&lt;/h3&gt;

&lt;p&gt;Start the worker Virtual Machine, login as root, change the host name as it can't be the same with the master: &lt;code&gt;hostnamectl set-hostname 'worker'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, execute the worker nodes joining command just noted, ignoring the &lt;code&gt;hostname could not be reached&lt;/code&gt; warnings since we didn't and don't need to configure the DNS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F11.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F11.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then wait for the worker to be available, Done!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhollowmansblog.files.wordpress.com%2F2022%2F01%2F12.png"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>linux</category>
      <category>cloud</category>
      <category>opensource</category>
    </item>
    <item>
      <title>GitHub Issues to Wechat</title>
      <dc:creator>Hollow Man</dc:creator>
      <pubDate>Tue, 30 Nov 2021 15:09:56 +0000</pubDate>
      <link>https://dev.to/hollowman6/github-issues-to-wechat-4klk</link>
      <guid>https://dev.to/hollowman6/github-issues-to-wechat-4klk</guid>
      <description>&lt;h3&gt;
  
  
  My Workflow
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/HollowMan6"&gt;
        HollowMan6
      &lt;/a&gt; / &lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat"&gt;
        GitHub-Issues-to-Wechat
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Send GitHub Issues, PRs or Discussions Updates to Wechat.(将 GitHub Issues, PRs 或者 Discussions 更新消息发送到微信)
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Send timed message to Wechat&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/graphs/commit-activity"&gt;&lt;img src="https://camo.githubusercontent.com/94649b494ef7a3e3e5116f1ab2d07001f62754f0a791d6de77711246587cc332/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f486f6c6c6f774d616e362f4769744875622d4973737565732d746f2d576563686174" alt="last-commit"&gt;&lt;/a&gt;
&lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/releases"&gt;&lt;img src="https://camo.githubusercontent.com/23e8cf1328573ad53b2f48faf0ce27e7cc7e5c893f0ded412bec934ea6ac0ce8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652d646174652f486f6c6c6f774d616e362f4769744875622d4973737565732d746f2d576563686174" alt="release-date"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/workflows/Python%20package/badge.svg"&gt;&lt;img src="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/workflows/Python%20package/badge.svg" alt="Python package"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/HollowMan6?tab=followers"&gt;&lt;img src="https://camo.githubusercontent.com/8441e22aa4e54675be52375e55951f0aaa6d809964cf71479073768aec57bfd4/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f666f6c6c6f776572732f486f6c6c6f774d616e363f7374796c653d736f6369616c" alt="Followers"&gt;&lt;/a&gt;
&lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/watchers"&gt;&lt;img src="https://camo.githubusercontent.com/964870ec6ba3da671b3fe6d84f5191651bc8094535f85078b810522131538aa1/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f77617463686572732f486f6c6c6f774d616e362f4769744875622d4973737565732d746f2d5765636861743f7374796c653d736f6369616c" alt="watchers"&gt;&lt;/a&gt;
&lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/stargazers"&gt;&lt;img src="https://camo.githubusercontent.com/61f30ab1fcd5b6c9931871565b04be13e7f988316b17b064c9d625557eb6eb8d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f486f6c6c6f774d616e362f4769744875622d4973737565732d746f2d5765636861743f7374796c653d736f6369616c" alt="stars"&gt;&lt;/a&gt;
&lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/network/members"&gt;&lt;img src="https://camo.githubusercontent.com/91f9af66ea68d3446b322dca93c6271f0ff3d73b9e1510171b67f0471c2e6492/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f666f726b732f486f6c6c6f774d616e362f4769744875622d4973737565732d746f2d5765636861743f7374796c653d736f6369616c" alt="forks"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://hollowman6.github.io/fund.html" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/b527a02f3970d48aa1570c5757c89e88d995616c74259938691a86d0ca26aad0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f2d2545322539442541342532304f70656e253230536f757263652d477265656e3f7374796c653d666c61742d737175617265266c6f676f3d476974687562266c6f676f436f6c6f723d7768697465266c696e6b3d68747470733a2f2f686f6c6c6f776d616e362e6769746875622e696f2f66756e642e68746d6c" alt="Open Source Love"&gt;&lt;/a&gt;
&lt;a href="https://opensource.org/licenses/GPL-3.0/" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/2f706a3275e4a48dc85ec930933303f3417d3b91d20943e25c8b66acdd223d53/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d47504c2d626c7565" alt="GPL Licence"&gt;&lt;/a&gt;
&lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/archive/master.zip"&gt;&lt;img src="https://camo.githubusercontent.com/2992a9308444d1405df6e2a3a7ebb935e1357f68664b78846563bc7fa1eb66e0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f7265706f2d73697a652f486f6c6c6f774d616e362f4769744875622d4973737565732d746f2d5765636861742e737667" alt="Repo-Size"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://lgtm.com/projects/g/HollowMan6/GitHub-Issues-to-Wechat/alerts/" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/be9ed6343ad5ff0ae14313fd773c65cb324f901d430db197cd41a42c3f6cc99d/68747470733a2f2f696d672e736869656c64732e696f2f6c67746d2f616c657274732f672f486f6c6c6f774d616e362f4769744875622d4973737565732d746f2d5765636861742e7376673f6c6f676f3d6c67746d266c6f676f57696474683d3138" alt="Total alerts"&gt;&lt;/a&gt;
&lt;a href="https://lgtm.com/projects/g/HollowMan6/GitHub-Issues-to-Wechat/context:python" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/4c817969c62ba911dafd3d3aa03597423b9fbf97140431ff6b4c24a60fc77a6f/68747470733a2f2f696d672e736869656c64732e696f2f6c67746d2f67726164652f707974686f6e2f672f486f6c6c6f774d616e362f4769744875622d4973737565732d746f2d5765636861742e7376673f6c6f676f3d6c67746d266c6f676f57696474683d3138" alt="Language grade: Python"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(中文版本在下方)&lt;/p&gt;
&lt;p&gt;Send GitHub Issues, PRs or Discussions Updates to Wechat&lt;/p&gt;
&lt;p&gt;Source Github Repository Link: &lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat"&gt;https://github.com/HollowMan6/GitHub-Issues-to-Wechat&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
Please &lt;strong&gt;★Star&lt;/strong&gt; if you think it's great!&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/network/dependencies"&gt;Python library dependency&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-WechatGitHub-Issues-to-Wechat.py"&gt;Source Code&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
Example &lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat.github/workflows/message.yml"&gt;Workflow&lt;/a&gt;
&lt;/h3&gt;
&lt;h2&gt;
Usage&lt;/h2&gt;
&lt;p&gt;you can fork this repository first, and then create Actions Secrets and set related settings in your forked repository (click in the order of 1, 2 and 3 as shown in the figure below).&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/HollowMan6/Wechat-Timed-Message/raw/main/img/secrets.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BhLzNcuo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/HollowMan6/Wechat-Timed-Message/raw/main/img/secrets.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can choose one or more of the following three push platforms to receive pushed messages:&lt;/p&gt;
&lt;h3&gt;
PushPlus(Recommended)&lt;/h3&gt;
&lt;p&gt;First &lt;a href="https://www.pushplus.plus/push1.html" rel="nofollow"&gt;log into pushplus&lt;/a&gt;, and then find your token in pushplus website, create a actions secret with the name of &lt;code&gt;PPTOKEN&lt;/code&gt; and the value of your token value, and then one-to-one push the related information results.&lt;/p&gt;
&lt;p&gt;If you need to push the related information to multiple Wechat accounts, that is, one-to-many push, you need to create a group, write down the group code…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Maintainer Must-Haves&lt;/p&gt;

&lt;h3&gt;
  
  
  Yaml File or Link to Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/blob/main/.github/workflows/message.yml"&gt;https://github.com/HollowMan6/GitHub-Issues-to-Wechat/blob/main/.github/workflows/message.yml&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The Blog Post About the Project
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://dev.to/hollowman6/a-workflow-for-sending-github-issues-prs-or-discussions-updates-to-wechat-1b7d"&gt;https://dev.to/hollowman6/a-workflow-for-sending-github-issues-prs-or-discussions-updates-to-wechat-1b7d&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Source Code for WeChat Message pushing
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/blob/main/GitHub-Issues-to-Wechat.py"&gt;https://github.com/HollowMan6/GitHub-Issues-to-Wechat/blob/main/GitHub-Issues-to-Wechat.py&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Docker File
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/blob/main/Dockerfile"&gt;https://github.com/HollowMan6/GitHub-Issues-to-Wechat/blob/main/Dockerfile&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Docker File
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/HollowMan6/GitHub-Issues-to-Wechat/blob/main/Dockerfile"&gt;https://github.com/HollowMan6/GitHub-Issues-to-Wechat/blob/main/Dockerfile&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  View on GitHub Marketplace
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/marketplace/actions/github-issues-to-wechat"&gt;https://github.com/marketplace/actions/github-issues-to-wechat&lt;/a&gt;&lt;/p&gt;

</description>
      <category>actionshackathon21</category>
    </item>
  </channel>
</rss>
