<?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: Shoichi Okaniwa</title>
    <description>The latest articles on DEV Community by Shoichi Okaniwa (@segur).</description>
    <link>https://dev.to/segur</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%2F705759%2F09c59154-e398-4141-b9b6-6107d3f64aaa.jpeg</url>
      <title>DEV Community: Shoichi Okaniwa</title>
      <link>https://dev.to/segur</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/segur"/>
    <language>en</language>
    <item>
      <title>Executing Git Commands from Unity's C#</title>
      <dc:creator>Shoichi Okaniwa</dc:creator>
      <pubDate>Wed, 22 Apr 2026 15:23:13 +0000</pubDate>
      <link>https://dev.to/segur/unitynockaragitwokou-ku-4b9e</link>
      <guid>https://dev.to/segur/unitynockaragitwokou-ku-4b9e</guid>
      <description>&lt;h1&gt;
  
  
  Executing Git Commands from Unity's C
&lt;/h1&gt;

&lt;p&gt;I recently had the opportunity to execute Git commands from a C# editor extension script in Unity. Here, I'll summarize the process so I won't forget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample Command
&lt;/h2&gt;

&lt;p&gt;As an example, let's execute the following command from Unity's C#:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config core.autocrlf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command checks if the feature to automatically convert line endings is enabled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample Code
&lt;/h2&gt;

&lt;p&gt;Below is the sample code. By calling &lt;code&gt;GetAutocrlf&lt;/code&gt; externally, the command will be executed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Diagnostics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEditor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Debug&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GitCommandPractice&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Check Git's autocrlf setting.&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;GetAutocrlf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Retrieve the git path.&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;gitPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetGitPath&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Set the git command.&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;gitCommand&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"config core.autocrlf"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Execute the command and get standard output.&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;autocrlf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetStandardOutputFromProcess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gitPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gitCommand&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;autocrlf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Retrieve the git executable path.&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;returns&amp;gt;Path of Git&amp;lt;/returns&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetGitPath&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// For Mac&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;platform&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;RuntimePlatform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OSXEditor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Possible paths&lt;/span&gt;
            &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;exePaths&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s"&gt;"/usr/local/bin/git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"/usr/bin/git"&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

            &lt;span class="c1"&gt;// First found existing path&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;exePaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exePath&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exePath&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// For Windows, this is sufficient&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"git"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Execute a command and get the standard output.&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;param name="exePath"&amp;gt;Path to executable&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;param name="arguments"&amp;gt;Command line arguments&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;returns&amp;gt;Standard output&amp;lt;/returns&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetStandardOutputFromProcess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;exePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Set process start conditions.&lt;/span&gt;
        &lt;span class="n"&gt;ProcessStartInfo&lt;/span&gt; &lt;span class="n"&gt;startInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ProcessStartInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;FileName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;exePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Arguments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;WindowStyle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ProcessWindowStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hidden&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;UseShellExecute&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;RedirectStandardOutput&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="c1"&gt;// Start the process.&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Process&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startInfo&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Get the standard output.&lt;/span&gt;
            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StandardOutput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadToEnd&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="c1"&gt;// Wait for the process to exit or time out.&lt;/span&gt;
            &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitForExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeoutPeriod&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Explanation
&lt;/h2&gt;

&lt;p&gt;This process uses C#'s &lt;code&gt;Process&lt;/code&gt; to execute Git commands and read their standard output.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;GetGitPath()&lt;/code&gt;, the path to the Git executable is retrieved. Generally, it should be sufficient to simply specify &lt;code&gt;git&lt;/code&gt; since the path to the Git executable is typically registered in the environment variable 'Path'. However, in my Mac environment, this was not enough, so I explicitly hard-coded two options: &lt;code&gt;/usr/local/bin/git&lt;/code&gt; and &lt;code&gt;/usr/bin/git&lt;/code&gt;, using whichever is found.&lt;/p&gt;

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

&lt;p&gt;In creating this article, I referred to the following resource. Thank you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://csharp.keicode.com/topics/capture-stdout.php" rel="noopener noreferrer"&gt;Method to Capture the Standard Output of a Child Process&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>c</category>
      <category>unity3d</category>
    </item>
    <item>
      <title>Trying Async Entry Listing and Creation with contentful-management</title>
      <dc:creator>Shoichi Okaniwa</dc:creator>
      <pubDate>Tue, 21 Apr 2026 15:19:45 +0000</pubDate>
      <link>https://dev.to/segur/contentful-managementdeentorino-lan-qu-de-toxin-gui-zuo-cheng-woasyncdeyatutemiru-pk8</link>
      <guid>https://dev.to/segur/contentful-managementdeentorino-lan-qu-de-toxin-gui-zuo-cheng-woasyncdeyatutemiru-pk8</guid>
      <description>&lt;h1&gt;
  
  
  Using async with contentful-management to List and Create Entries
&lt;/h1&gt;

&lt;p&gt;I recently experimented with the JavaScript SDK for contentful-management and wanted to jot down my findings before I forget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation
&lt;/h2&gt;

&lt;p&gt;Create a Contentful account and space. This &lt;a href="https://blog.cloud-acct.com/posts/blog-contentful-signup/" rel="noopener noreferrer"&gt;article&lt;/a&gt; helped me understand the process clearly.&lt;/p&gt;

&lt;p&gt;Install the necessary packages for your Node.js project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;dotenv
npm &lt;span class="nb"&gt;install &lt;/span&gt;contentful-management
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in the same directory as your &lt;code&gt;package.json&lt;/code&gt; and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;personal_access_token&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your_personal_access_token&lt;/span&gt;
&lt;span class="py"&gt;space_id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your_space_id&lt;/span&gt;
&lt;span class="py"&gt;environment_id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your_environment_id_or_master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to create a Personal Access Token specifically for the Contentful Management API, separate from the Delivery and Preview API keys. For details, check the &lt;a href="https://www.contentful.com/help/personal-access-tokens/" rel="noopener noreferrer"&gt;official page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieving a List of Entries from Contentful
&lt;/h2&gt;

&lt;p&gt;In Contentful, each piece of data is called an entry, similar to a record in a relational database.&lt;/p&gt;

&lt;p&gt;Here's the source code to obtain a list of entries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;

&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unhandledRejection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contentful&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;contentful-management&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;contentful&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;personal_access_token&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;space&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;space_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;space&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEnvironment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEntries&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Registering an Entry in Contentful
&lt;/h2&gt;

&lt;p&gt;A content model in Contentful is akin to a table in a database. We will create a new entry in this model. First, create it as a draft, and then publish it.&lt;/p&gt;

&lt;p&gt;Here's the source code:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;fields&lt;/code&gt; section varies depending on your content model, so adjust as necessary. If you've changed Contentful's &lt;code&gt;Settings &amp;gt; Locales&lt;/code&gt; to &lt;code&gt;ja&lt;/code&gt;, replace &lt;code&gt;en-US&lt;/code&gt; with &lt;code&gt;ja&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;

&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unhandledRejection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contentful&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;contentful-management&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;contentful&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;personal_access_token&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;space&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;space_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;space&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEnvironment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;environment_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;draftEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createEntry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hoge_content_type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hoge_id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-US&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hoge_name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;publishedEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;draftEntry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Published entry ID: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;publishedEntry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to change &lt;code&gt;'hoge_content_type'&lt;/code&gt; to your content model's ID as needed.&lt;/p&gt;

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

&lt;p&gt;I referred to the following pages when creating this article. Many thanks for the clear information.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.contentful.com/developers/docs/references/content-management-api/" rel="noopener noreferrer"&gt;Content Management API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nju33.com/contentful/API%20%E3%82%92%E7%94%A8%E3%81%84%E3%81%9F%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%83%BC%E3%81%AE%E5%8F%96%E5%BE%97%E3%81%A8%E6%9B%B4%E6%96%B0" rel="noopener noreferrer"&gt;Fetching and Updating Entries with APIs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.cloud-acct.com/posts/blog-contentful-signup/" rel="noopener noreferrer"&gt;Explained with Images: How to Use Contentful - Learn Initial Setup and Menu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.contentful.com/help/personal-access-tokens/" rel="noopener noreferrer"&gt;Personal Access Tokens&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>contentful</category>
    </item>
    <item>
      <title>Using UdonSharp to Force Things Through Since Timeline Doesn’t Work in VRChat</title>
      <dc:creator>Shoichi Okaniwa</dc:creator>
      <pubDate>Mon, 20 Apr 2026 15:21:14 +0000</pubDate>
      <link>https://dev.to/segur/vrchatdetimelinegashi-enaikaraudonsharpdegoriya-sisitemita-43cl</link>
      <guid>https://dev.to/segur/vrchatdetimelinegashi-enaikaraudonsharpdegoriya-sisitemita-43cl</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;I created a workaround for the absence of Timeline in VRChat by using UdonSharp to manually control when objects appear and disappear based on time.&lt;/p&gt;

&lt;p&gt;Here's what I ended up creating:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1256957066393968640-628" src="https://platform.twitter.com/embed/Tweet.html?id=1256957066393968640"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1256957066393968640-628');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1256957066393968640&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h1&gt;
  
  
  Unity2018 and the Loss of Timeline in VRChat
&lt;/h1&gt;

&lt;p&gt;In the VRChat days of Unity2017, you could use Timeline effectively for creating worlds where object visibility aligned with music, like a particle live show. However, Timeline became unavailable in VRChat after the transition to Unity2018.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1256620569065185280-228" src="https://platform.twitter.com/embed/Tweet.html?id=1256620569065185280"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1256620569065185280-228');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1256620569065185280&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h1&gt;
  
  
  Attempting with UdonSharp
&lt;/h1&gt;

&lt;p&gt;I decided to create my own implementation of Timeline functionality. While learning UdonSharp (U#), I attempted this using U#.&lt;/p&gt;

&lt;p&gt;A handy guide for setting up the UdonSharp development environment was &lt;a href="https://hatuxes.hatenablog.jp/entry/2020/04/05/013310" rel="noopener noreferrer"&gt;U# Intro ①&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementing with Udon
&lt;/h1&gt;

&lt;p&gt;Here is the completed code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UdonSharp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine.UI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;VRC.SDKBase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;VRC.Udon&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PseudoTimeline&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UdonSharpBehaviour&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Button label&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="n"&gt;buttonLabel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// List of game objects to control&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;GameObject&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;cylinder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// List of start times&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// List of durations&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Elapsed time&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;UdonSynced&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UdonSyncMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Playing flag&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;UdonSynced&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UdonSyncMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isPlaying&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Start as stopped&lt;/span&gt;
        &lt;span class="n"&gt;isPlaying&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Interact&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Change owner for the button&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;Networking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsOwner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Networking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LocalPlayer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Networking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetOwner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Networking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LocalPlayer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Initialize elapsed time&lt;/span&gt;
        &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.0f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Toggle between play and stop&lt;/span&gt;
        &lt;span class="n"&gt;isPlaying&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isPlaying&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isPlaying&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Change button label&lt;/span&gt;
            &lt;span class="n"&gt;buttonLabel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"■"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Count up elapsed time&lt;/span&gt;
            &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cylinder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Start showing&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;cylinder&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;SetActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="c1"&gt;// Stop showing&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;cylinder&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;SetActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Change button label&lt;/span&gt;
            &lt;span class="n"&gt;buttonLabel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"▶"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Hide everything&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cylinder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;cylinder&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;SetActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attach &lt;code&gt;Udon Behaviour&lt;/code&gt; to a suitable Cube and set the &lt;code&gt;Source Script&lt;/code&gt; to the above code.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting Public Variables
&lt;/h1&gt;

&lt;p&gt;Set the Public Variables as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzqjz7oyg1v4x0zh5xis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzqjz7oyg1v4x0zh5xis.png" alt="image.png" width="541" height="731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create and assign an appropriate &lt;code&gt;Text&lt;/code&gt; to &lt;code&gt;Button Label&lt;/code&gt;. It changes to &lt;code&gt;■&lt;/code&gt; when playing and &lt;code&gt;▶&lt;/code&gt; when stopped.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;Cylinder&lt;/code&gt;, set the GameObjects you wish to toggle visibility for. I prepared five cylinder objects.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Start Time&lt;/code&gt; specifies the show start time for each GameObject. You need the same amount as &lt;code&gt;Cylinder&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Duration&lt;/code&gt; is the play time for each GameObject. You need the same number as &lt;code&gt;Cylinder&lt;/code&gt;. The hide end time is the start time plus this duration.&lt;/p&gt;

&lt;h1&gt;
  
  
  Results
&lt;/h1&gt;

&lt;p&gt;A simple particle live presentation can be created as shown below:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1256957066393968640-901" src="https://platform.twitter.com/embed/Tweet.html?id=1256957066393968640"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1256957066393968640-901');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1256957066393968640&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h1&gt;
  
  
  About UdonSynced
&lt;/h1&gt;

&lt;p&gt;The attributes &lt;code&gt;[UdonSynced(UdonSyncMode.None)]&lt;/code&gt; are attached to &lt;code&gt;isPlaying&lt;/code&gt; and &lt;code&gt;currentTime&lt;/code&gt;. This allows multiple users to view the particle live simultaneously.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In writing this article, I referred to the following articles. Thank you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hatuxes.hatenablog.jp/entry/2020/04/05/013310" rel="noopener noreferrer"&gt;U# Intro ①&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hatuxes.hatenablog.jp/entry/2020/04/05/013323" rel="noopener noreferrer"&gt;U# Intro ②&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>unity3d</category>
      <category>vrchat</category>
      <category>udon</category>
      <category>udonsharp</category>
    </item>
    <item>
      <title>Writing Python Code to Convert Quaternions to Z-Y-X Euler Angles</title>
      <dc:creator>Shoichi Okaniwa</dc:creator>
      <pubDate>Sun, 19 Apr 2026 14:48:07 +0000</pubDate>
      <link>https://dev.to/segur/pythondekuotanionwoz-y-xxi-oirajiao-nibian-huan-surukodoshu-itemita-2kcm</link>
      <guid>https://dev.to/segur/pythondekuotanionwoz-y-xxi-oirajiao-nibian-huan-surukodoshu-itemita-2kcm</guid>
      <description>&lt;h1&gt;
  
  
  Writing Code to Convert Quaternions to Z-Y-X Euler Angles in Python
&lt;/h1&gt;

&lt;p&gt;I needed to calculate Z-Y-X Euler angles from quaternions.&lt;/p&gt;

&lt;p&gt;Moreover, the task required me to write the code in Python 2.7, so I couldn't use handy tools like &lt;code&gt;scipy.spatial.transform.Rotation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When I did some research, I found a sample code in C++ on Wikipedia.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Source_Code_2" rel="noopener noreferrer"&gt;Wikipedia / Quaternion to Euler Angles Conversion&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing in Python
&lt;/h2&gt;

&lt;p&gt;Based on the Wikipedia sample code, I created a code in Python 2.7.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pyquaternion&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Quaternion&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;quaternion_to_euler_zyx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Convert quaternion to Z-Y-X Euler angles.

    Parameters
    ----------
    q : Quaternion
        Quaternion (in pyquaternion format)

    Returns
    -------
    np.array
        Z-Y-X Euler angles
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="c1"&gt;# roll : rotation around x-axis
&lt;/span&gt;    &lt;span class="n"&gt;sinr_cosp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;cosr_cosp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;roll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;atan2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sinr_cosp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cosr_cosp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# pitch : rotation around y-axis
&lt;/span&gt;    &lt;span class="n"&gt;sinp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fabs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sinp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pitch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copysign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sinp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pitch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sinp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# yaw : rotation around z-axis
&lt;/span&gt;    &lt;span class="n"&gt;siny_cosp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;cosy_cosp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;yaw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;atan2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;siny_cosp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cosy_cosp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Euler angles
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;degrees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roll&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
        &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;degrees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
        &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;degrees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yaw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  NumPy 1.16.6
&lt;/h3&gt;

&lt;p&gt;Used for vector calculations. Version 1.16.6 seems to be the latest one supporting Python 2.7.&lt;/p&gt;

&lt;h3&gt;
  
  
  PyQuaternion 0.9.5
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;PyQuaternion&lt;/code&gt; is used for quaternion calculations.&lt;/p&gt;

&lt;p&gt;While &lt;code&gt;numpy-quaternion&lt;/code&gt; might work better with NumPy, it could not be installed in the Python 2.7 environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Easier with SciPy in Python 3
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;scipy.spatial.transform.Rotation&lt;/code&gt; makes it simpler if you're using Python 3 or later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pyquaternion&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Quaternion&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;scipy.spatial.transform&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Rotation&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;quaternion_to_euler_zyx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_quat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_euler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;zyx&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;degrees&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, &lt;code&gt;scipy.spatial.transform.Rotation&lt;/code&gt; does not support Python 2.7.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I'm mostly accustomed to dealing with Unity's Z-X-Y Euler angles, so working with Z-Y-X was quite confusing. I referred to the following articles while creating this post. Thank you for the detailed insights!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Source_Code_2" rel="noopener noreferrer"&gt;Wikipedia / Quaternion to Euler Angles Conversion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kamino.hatenablog.com/entry/scipy_rotation" rel="noopener noreferrer"&gt;Kamino's Memo / Handling 3D Rotations with the scipy Rotation Module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.transform.Rotation.html" rel="noopener noreferrer"&gt;scipy.spatial.transform.Rotation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>scipy</category>
      <category>numpy</category>
    </item>
    <item>
      <title>12 Quiz Questions to Truly Understand Semantic Versioning</title>
      <dc:creator>Shoichi Okaniwa</dc:creator>
      <pubDate>Sat, 18 Apr 2026 14:47:49 +0000</pubDate>
      <link>https://dev.to/segur/semanteitukubaziyoningugayokuwakarukuizu12wen-38p2</link>
      <guid>https://dev.to/segur/semanteitukubaziyoningugayokuwakarukuizu12wen-38p2</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;I organized a seminar on semantic versioning for beginners using package management tools. The quiz format we used was well-received, so I am sharing the materials from that session.&lt;/p&gt;

&lt;p&gt;By answering these questions, you will gain a good understanding of how semantic versioning works!&lt;/p&gt;

&lt;p&gt;Give it a try!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Semantic Versioning?
&lt;/h2&gt;

&lt;p&gt;This is one way to assign version numbers, often abbreviated as SemVer.&lt;/p&gt;

&lt;p&gt;npm, a package management tool for Node.js, is a well-known example of using semantic versioning.&lt;br&gt;
&lt;a href="https://docs.npmjs.com/about-semantic-versioning" rel="noopener noreferrer"&gt;Learn more here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For detailed specifications of semantic versioning, please refer to the following page:&lt;br&gt;
&lt;a href="https://semver.org/lang/en/" rel="noopener noreferrer"&gt;https://semver.org/lang/en/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, we will refer to the page mentioned above as the "specifications."&lt;/p&gt;

&lt;h1&gt;
  
  
  Semantic Versioning Quiz
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Question 1: Which of the following version formats is correct according to semantic versioning?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 0.01.0&lt;/li&gt;
&lt;li&gt;[ ] 0.1.3.1&lt;/li&gt;
&lt;li&gt;[ ] 1-1-0&lt;/li&gt;
&lt;li&gt;[ ] 1.2.a&lt;/li&gt;
&lt;li&gt;[ ] 3,9,2&lt;/li&gt;
&lt;li&gt;[ ] 2.-1.3&lt;/li&gt;
&lt;li&gt;[ ] 0.11.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer and Explanation&lt;br&gt;
Correct answer: &lt;strong&gt;0.11.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the specifications:&lt;/p&gt;

&lt;p&gt;&amp;gt; A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative integers and MUST NOT contain leading zeroes. X is the major version, Y is the minor version, and Z is the patch version. Each element MUST increase numerically. For example: 1.9.0 -&amp;gt; 1.10.0 -&amp;gt; 1.11.0.&lt;/p&gt;

&lt;p&gt;Explanation for each choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 0.01.0: Incorrect because leading zeroes are not allowed.&lt;/li&gt;
&lt;li&gt;[ ] 0.1.3.1: Incorrect because the format must be X.Y.Z.&lt;/li&gt;
&lt;li&gt;[ ] 1-1-0: Incorrect because the format must be X.Y.Z.&lt;/li&gt;
&lt;li&gt;[ ] 1.2.a: Incorrect because X, Y, and Z must be non-negative integers.&lt;/li&gt;
&lt;li&gt;[ ] 3,9,2: Incorrect because the format must be X.Y.Z.&lt;/li&gt;
&lt;li&gt;[ ] 2.-1.3: Incorrect because X, Y, and Z must be non-negative integers.&lt;/li&gt;
&lt;li&gt;[x] 0.11.0: Correct.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Question 2: A bug was found in version 1.1.9! After fixing the bug, what will the version number be?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 1.1.9.1&lt;/li&gt;
&lt;li&gt;[ ] 1.1.10&lt;/li&gt;
&lt;li&gt;[ ] 1.2.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer and Explanation&lt;br&gt;
Correct answer: &lt;strong&gt;1.1.10&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the specifications:&lt;/p&gt;

&lt;p&gt;&amp;gt; Patch version Z (x.y.Z | x &amp;gt; 0) MUST be incremented if only backward-compatible bug fixes are introduced. A bug fix is defined as an internal change that fixes incorrect behavior.&lt;/p&gt;

&lt;p&gt;Explanation for each choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 1.1.9.1: Incorrect because the format must be X.Y.Z.&lt;/li&gt;
&lt;li&gt;[x] 1.1.10: Correct as the patch is incremented for a bug fix.&lt;/li&gt;
&lt;li&gt;[ ] 1.2.0: Incorrect since no new functionality was added.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Question 3: A new path (new feature) was added to the Web API in version 1.2.5! The existing features have not changed. What will the version number be?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 1.2.5.1&lt;/li&gt;
&lt;li&gt;[ ] 1.2.6&lt;/li&gt;
&lt;li&gt;[ ] 1.3.0&lt;/li&gt;
&lt;li&gt;[ ] 1.3.5&lt;/li&gt;
&lt;li&gt;[ ] 2.0.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer and Explanation&lt;br&gt;
Correct answer: &lt;strong&gt;1.3.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the specifications:&lt;/p&gt;

&lt;p&gt;&amp;gt; Minor version Y (x.Y.z | x &amp;gt; 0) MUST be incremented if new, backward-compatible functionality is introduced to the public API. It MAY include patch level changes. Patch version MUST be reset to 0 when minor version is incremented.&lt;/p&gt;

&lt;p&gt;Explanation for each choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 1.2.5.1: Incorrect because the format must be X.Y.Z.&lt;/li&gt;
&lt;li&gt;[ ] 1.2.6: Incorrect because a new feature was added, not a bug fix.&lt;/li&gt;
&lt;li&gt;[x] 1.3.0: Correct as new functionality means incrementing the minor version.&lt;/li&gt;
&lt;li&gt;[ ] 1.3.5: Incorrect because patch version must be reset when the minor is incremented.&lt;/li&gt;
&lt;li&gt;[ ] 2.0.0: Incorrect as the change is backward-compatible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Question 4: At the early stage of development, what is the safest initial version number? (It's also a matter of convention)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 0.0.0&lt;/li&gt;
&lt;li&gt;[ ] 0.0.1&lt;/li&gt;
&lt;li&gt;[ ] 0.1.0&lt;/li&gt;
&lt;li&gt;[ ] 1.0.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer and Explanation&lt;br&gt;
Correct answer: &lt;strong&gt;0.1.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the specifications:&lt;/p&gt;

&lt;p&gt;&amp;gt; In the early stages of development, version numbers can safely start at 0.1.0 and increment minor version for each subsequent release.&lt;/p&gt;

&lt;p&gt;Explanation for each choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 0.0.0: There's no harm here, but the specifications suggest starting at 0.1.0.&lt;/li&gt;
&lt;li&gt;[ ] 0.0.1: There's no harm here, but the specifications suggest starting at 0.1.0.&lt;/li&gt;
&lt;li&gt;[x] 0.1.0: Correct as per the specifications.&lt;/li&gt;
&lt;li&gt;[ ] 1.0.0: Incorrect since the software is not yet public.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Question 5: After refactoring version 1.2.7, the processing speed doubled! The API specification hasn't changed. What will the version number be?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Remain 1.2.7&lt;/li&gt;
&lt;li&gt;[ ] 1.2.7.1&lt;/li&gt;
&lt;li&gt;[ ] 1.2.8&lt;/li&gt;
&lt;li&gt;[ ] 1.3.0&lt;/li&gt;
&lt;li&gt;[ ] 2.0.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer and Explanation&lt;br&gt;
Correct answer: &lt;strong&gt;1.2.7&lt;/strong&gt; or &lt;strong&gt;1.3.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the specifications:&lt;/p&gt;

&lt;p&gt;&amp;gt; Minor version Y (x.Y.z | x &amp;gt; 0) MAY be incremented if significant new functionality or improvements are added internally, even with compatible API.&lt;/p&gt;

&lt;p&gt;Explanation for each choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[x] Remain 1.2.7: Correct; no external change.&lt;/li&gt;
&lt;li&gt;[ ] 1.2.7.1: Incorrect because the format must be X.Y.Z.&lt;/li&gt;
&lt;li&gt;[ ] 1.2.8: Incorrect as there's no bug fix.&lt;/li&gt;
&lt;li&gt;[x] 1.3.0: Correct if internal changes warrant a version increment.&lt;/li&gt;
&lt;li&gt;[ ] 2.0.0: Incorrect since backward compatibility is maintained.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Question 6: You're developing both a mobile app and a Web API. The Web API, version 0.3.5, is only used by the mobile app. The mobile app is now released on the App Store! What will the Web API version be?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Remain 0.3.5&lt;/li&gt;
&lt;li&gt;[ ] 0.3.6&lt;/li&gt;
&lt;li&gt;[ ] 0.4.0&lt;/li&gt;
&lt;li&gt;[ ] 1.0.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer and Explanation&lt;br&gt;
Correct answer: &lt;strong&gt;0.3.5&lt;/strong&gt; or &lt;strong&gt;1.0.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the specifications:&lt;/p&gt;

&lt;p&gt;&amp;gt; Version 1.0.0 defines a public API. It should be released if the software is used in production or if significant dependencies exist.&lt;/p&gt;

&lt;p&gt;Explanation for each choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[x] Remain 0.3.5: Correct if no public use.&lt;/li&gt;
&lt;li&gt;[ ] 0.3.6: Incorrect as no bug fix.&lt;/li&gt;
&lt;li&gt;[ ] 0.4.0: Incorrect as no change in functionality.&lt;/li&gt;
&lt;li&gt;[x] 1.0.0: Correct if the API is now public via the App Store.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Question 7: You changed a feature specification in version 1.12.6! It's no longer backward-compatible. What will the version number be?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 1.12.7&lt;/li&gt;
&lt;li&gt;[ ] 1.13.0&lt;/li&gt;
&lt;li&gt;[ ] 2.0.0&lt;/li&gt;
&lt;li&gt;[ ] 2.1.0&lt;/li&gt;
&lt;li&gt;[ ] 2.12.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer and Explanation&lt;br&gt;
Correct answer: &lt;strong&gt;2.0.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the specifications:&lt;/p&gt;

&lt;p&gt;&amp;gt; Major version X (X.y.z | X &amp;gt; 0) MUST be incremented if any backward-incompatible changes are introduced to the public API. Minor and patch versions MUST be reset to 0.&lt;/p&gt;

&lt;p&gt;Explanation for each choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 1.12.7: Incorrect as major version must increase with incompatibility.&lt;/li&gt;
&lt;li&gt;[ ] 1.13.0: Incorrect as major version must increase with incompatibility.&lt;/li&gt;
&lt;li&gt;[x] 2.0.0: Correct for backward incompatibility.&lt;/li&gt;
&lt;li&gt;[ ] 2.1.0: Incorrect; minor and patch reset with major change.&lt;/li&gt;
&lt;li&gt;[ ] 2.12.0: Incorrect; minor and patch reset with major change.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Question 8: You changed a feature in version 0.3.6! It's no longer backward-compatible, but we are still in early development where frequent changes are expected. What's a prudent version number?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 0.4.0&lt;/li&gt;
&lt;li&gt;[ ] 1.0.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer and Explanation&lt;br&gt;
Correct answer: &lt;strong&gt;0.4.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the specifications:&lt;/p&gt;

&lt;p&gt;&amp;gt; Major version zero (0.y.z) indicates development. Changes can occur at any time. Do not assume stability.&lt;/p&gt;

&lt;p&gt;&amp;gt; 1.0.0 should be released if the software is used in production or is stable and relied upon.&lt;/p&gt;

&lt;p&gt;Explanation for each choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[x] 0.4.0: Correct for early development, using a minor increment.&lt;/li&gt;
&lt;li&gt;[ ] 1.0.0: Incorrect as it's still in early development.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Question 9: A bug was found in 1.5.2! You've fixed it and added a new feature without changing existing specifications. What's the version number now?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 1.5.3&lt;/li&gt;
&lt;li&gt;[ ] 1.6.0&lt;/li&gt;
&lt;li&gt;[ ] 1.6.1&lt;/li&gt;
&lt;li&gt;[ ] 2.0.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer and Explanation&lt;br&gt;
Correct answer: &lt;strong&gt;1.6.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the specifications:&lt;/p&gt;

&lt;p&gt;&amp;gt; Minor version Y (x.Y.z | x &amp;gt; 0) MUST be incremented if backward-compatible functionality is added. Patch version should be reset.&lt;/p&gt;

&lt;p&gt;Explanation for each choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 1.5.3: Incorrect as minor must increase with functionality.&lt;/li&gt;
&lt;li&gt;[x] 1.6.0: Correct for adding functionality.&lt;/li&gt;
&lt;li&gt;[ ] 1.6.1: Incorrect as patch resets with a minor increment.&lt;/li&gt;
&lt;li&gt;[ ] 2.0.0: Incorrect since changes are backward-compatible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Question 10: After releasing version 2.6.3, a bug was immediately found and fixed in 30 seconds! What's the new version?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Remain 2.6.3&lt;/li&gt;
&lt;li&gt;[ ] 2.6.4&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer and Explanation&lt;br&gt;
Correct answer: &lt;strong&gt;2.6.4&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the specifications:&lt;/p&gt;

&lt;p&gt;&amp;gt; Once a versioned package is released, the contents must not be modified. Any errors must be corrected in a new version.&lt;/p&gt;

&lt;p&gt;Therefore, even if quickly adjusted, the version should be 2.6.4.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 11: You deprecated an API in version 1.14.3. What's the new version?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 1.14.4&lt;/li&gt;
&lt;li&gt;[ ] 1.15.0&lt;/li&gt;
&lt;li&gt;[ ] 2.0.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer and Explanation&lt;br&gt;
Correct answer: &lt;strong&gt;2.0.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the specifications:&lt;/p&gt;

&lt;p&gt;&amp;gt; If any public API is deprecated, the major version must increase due to loss of backward compatibility.&lt;/p&gt;

&lt;p&gt;Explanation for each choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 1.14.4: Incorrect since backward compatibility is lost.&lt;/li&gt;
&lt;li&gt;[ ] 1.15.0: Incorrect since backward compatibility is lost.&lt;/li&gt;
&lt;li&gt;[x] 2.0.0: Correct as major version increases with deprecation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Question 12: You plan to deprecate an API in version 1.11.1 but haven't done so yet. Documentation will mention this upcoming change. What's the version number?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Remain 1.11.1&lt;/li&gt;
&lt;li&gt;[ ] 1.11.2&lt;/li&gt;
&lt;li&gt;[ ] 1.12.0&lt;/li&gt;
&lt;li&gt;[ ] 2.0.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answer and Explanation&lt;br&gt;
Correct answer: &lt;strong&gt;1.12.0&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;According to the specifications:&lt;/p&gt;

&lt;p&gt;&amp;gt; If a public API is scheduled to be deprecated, you must increase the minor version.&lt;/p&gt;

&lt;p&gt;Explanation for each choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Remain 1.11.1: Incorrect since deprecation is planned, warranting a version change.&lt;/li&gt;
&lt;li&gt;[ ] 1.11.2: Incorrect since the minor version must increase with deprecation plans.&lt;/li&gt;
&lt;li&gt;[x] 1.12.0: Correct, as planned deprecation means bumping the minor version.&lt;/li&gt;
&lt;li&gt;[ ] 2.0.0: Incorrect since changes are still backward-compatible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The quiz format sparked quite an excitement at my workplace. Feel free to challenge your colleagues too.&lt;/p&gt;

&lt;p&gt;If there's any mistake in this quiz, please let me know.&lt;/p&gt;

&lt;p&gt;Thank you for participating.&lt;/p&gt;

</description>
      <category>version</category>
      <category>semver</category>
    </item>
    <item>
      <title>Trying a C++ Hello World with the Official GCC Docker Image</title>
      <dc:creator>Shoichi Okaniwa</dc:creator>
      <pubDate>Fri, 17 Apr 2026 15:04:02 +0000</pubDate>
      <link>https://dev.to/segur/gccnodockergong-shi-imezishi-tutecdehelloworldsitemita-392c</link>
      <guid>https://dev.to/segur/gccnodockergong-shi-imezishi-tutecdehelloworldsitemita-392c</guid>
      <description>&lt;h1&gt;
  
  
  Introduction to Handling C++ Code
&lt;/h1&gt;

&lt;p&gt;In our ongoing web service project, we need to work with C++ source code. Our goal is to ensure that this code compiles and runs in a Linux environment using GCC inside a Docker container. We are not using &lt;code&gt;make&lt;/code&gt; or focusing on minimizing the environment size for now.&lt;/p&gt;

&lt;p&gt;You can find the sample code created for this purpose &lt;a href="https://github.com/segurvita/docker-gcc-sample" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Searching for a Docker Image
&lt;/h1&gt;

&lt;p&gt;Searching for GCC on Docker Hub revealed an official image available &lt;a href="https://hub.docker.com/_/gcc/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We'll use this image (although there might be a lighter one available).&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating the C++ Source Code
&lt;/h1&gt;

&lt;p&gt;Let's create a simple &lt;code&gt;Hello World!&lt;/code&gt; program in C++.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;

int main()
{
    std::cout &amp;lt;&amp;lt; "Hello world!" &amp;lt;&amp;lt; std::endl;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Creating a Script for Compiling and Executing
&lt;/h1&gt;

&lt;p&gt;Here's a script to compile the C++ file. Place it in the same directory as your &lt;code&gt;.cpp&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

# Compile
g++ hello.cpp -o hello

# Execute
./hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Creating &lt;code&gt;docker-compose.yml&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;After pulling the official Docker image, we'll use it to execute &lt;code&gt;build.sh&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3'
services:
  gcc-cpp-sample:
    image: 'gcc:9.2'
    volumes:
      - ./cpp:/src/cpp
    working_dir: /src/cpp
    command: ./build.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure the &lt;code&gt;cpp&lt;/code&gt; folder is at the same level as &lt;code&gt;docker-compose.yml&lt;/code&gt;, and place &lt;code&gt;hello.cpp&lt;/code&gt; and &lt;code&gt;build.sh&lt;/code&gt; inside it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Execution!
&lt;/h1&gt;

&lt;p&gt;By executing the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the message &lt;code&gt;Hello World!&lt;/code&gt; was successfully displayed!&lt;/p&gt;

&lt;h1&gt;
  
  
  Sample Code
&lt;/h1&gt;

&lt;p&gt;You can find the sample code &lt;a href="https://github.com/segurvita/docker-gcc-sample" rel="noopener noreferrer"&gt;here&lt;/a&gt;. In addition to what's covered in this article, it also includes compiling and executing C language programs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Returning to GCC after about 10 years was a great mental exercise.&lt;/p&gt;

&lt;p&gt;This article was created with reference to the following resources. Thank you for the clear and informative articles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://qiita.com/seriru13/items/c2f5192615162c4c3f47" rel="noopener noreferrer"&gt;GCC Compilation Options Memo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ezoeryou.github.io/cpp-intro/#gcc-c%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E3%83%BC" rel="noopener noreferrer"&gt;Ryo Ezoe’s C++ Introduction/GCC: C++ Compiler&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, if you're concerned about the size of the official Docker image, you may want to consider Alpine Linux for a lighter environment. Here's a comprehensive guide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://qiita.com/Panda_Program/items/abbff0864fb65bdfe7d0" rel="noopener noreferrer"&gt;Docker + C Language Environment: Lightweight Alpine Linux is Good&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>c</category>
      <category>gcc</category>
      <category>docker</category>
    </item>
    <item>
      <title>Debugging Web Pages Viewed on iPhone</title>
      <dc:creator>Shoichi Okaniwa</dc:creator>
      <pubDate>Thu, 16 Apr 2026 15:44:57 +0000</pubDate>
      <link>https://dev.to/segur/iphonenosafaridebiao-shi-siteirupeziwomacnosafaridedebatugusuru-4k3m</link>
      <guid>https://dev.to/segur/iphonenosafaridebiao-shi-siteirupeziwomacnosafaridedebatugusuru-4k3m</guid>
      <description>&lt;h1&gt;
  
  
  Debugging Web Pages Viewed on iPhone
&lt;/h1&gt;

&lt;p&gt;While accessing the website under development with Safari on iPhone, I noticed it wasn't functioning correctly. Web browsers on Windows and Mac displayed it correctly, indicating an issue specific to iPhone.&lt;/p&gt;

&lt;p&gt;Upon researching, I found using Mac's Safari the simplest method for iPhone debugging and decided to give it a try successfully. To avoid forgetting, I've outlined it here.&lt;/p&gt;

&lt;h1&gt;
  
  
  Steps for iPhone
&lt;/h1&gt;

&lt;p&gt;First, open the &lt;code&gt;Settings&lt;/code&gt; app. Navigate to &lt;code&gt;Safari&lt;/code&gt; → &lt;code&gt;Advanced&lt;/code&gt; → and toggle &lt;code&gt;Web Inspector&lt;/code&gt; ON.&lt;/p&gt;

&lt;p&gt;Then, open the page you wish to debug in Safari on your iPhone.&lt;/p&gt;

&lt;h1&gt;
  
  
  Connecting iPhone and Mac
&lt;/h1&gt;

&lt;p&gt;Connect your iPhone and Mac via USB.&lt;/p&gt;

&lt;p&gt;If prompted with "Trust This Computer?" on the iPhone, tap &lt;code&gt;Trust&lt;/code&gt; and input your passcode.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.jsdelivr.net%2Fgh%2Fsegurvita%2Fsegur-article-assets%40main%2F2019-09-25_debugging-pages-from-iphone-safari-on-mac-safari%2Fa8075235-7e02-f5b1-16ca-13d4df3c53ef.jpeg" class="article-body-image-wrapper"&gt;&lt;img width="700" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.jsdelivr.net%2Fgh%2Fsegurvita%2Fsegur-article-assets%40main%2F2019-09-25_debugging-pages-from-iphone-safari-on-mac-safari%2Fa8075235-7e02-f5b1-16ca-13d4df3c53ef.jpeg" alt="ios12-iphone-x-home-trust-computer-alert.jpg" height="900"&gt;&lt;/a&gt;&lt;br&gt;
Source: &lt;a href="https://support.apple.com/ja-jp/HT202778" rel="noopener noreferrer"&gt;https://support.apple.com/ja-jp/HT202778&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Steps for Mac
&lt;/h1&gt;

&lt;p&gt;First, launch &lt;code&gt;Safari&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hover over the &lt;code&gt;Develop&lt;/code&gt; menu in the menu bar.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;Develop&lt;/code&gt; is not visible, go to the menu bar's &lt;code&gt;Safari&lt;/code&gt; → &lt;code&gt;Preferences&lt;/code&gt; → &lt;code&gt;Advanced&lt;/code&gt; and enable &lt;code&gt;Show Develop menu in menu bar&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hover over the &lt;code&gt;Develop&lt;/code&gt; menu, and you’ll see the iPhone device name listed. Hover over it to display the URLs of the pages open in Safari on your iPhone. Select the page you wish to debug.&lt;/p&gt;

&lt;p&gt;This will open the &lt;code&gt;Web Inspector&lt;/code&gt; window.&lt;/p&gt;

&lt;p&gt;You can now proceed with debugging.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I'm glad this could be done easily.&lt;/p&gt;

</description>
      <category>mac</category>
      <category>ios</category>
      <category>safari</category>
    </item>
    <item>
      <title>Handling 403 Errors When Uploading to S3 Signed URLs with Node.js</title>
      <dc:creator>Shoichi Okaniwa</dc:creator>
      <pubDate>Wed, 15 Apr 2026 15:11:23 +0000</pubDate>
      <link>https://dev.to/segur/nodejsdefa-xing-sitas3noshu-ming-fu-kiurlheatupurodosuruto403eraninaru-1n6o</link>
      <guid>https://dev.to/segur/nodejsdefa-xing-sitas3noshu-ming-fu-kiurlheatupurodosuruto403eraninaru-1n6o</guid>
      <description>&lt;h1&gt;
  
  
  Handling 403 Errors When Uploading to S3 Signed URLs with Node.js
&lt;/h1&gt;

&lt;p&gt;I encountered challenges uploading files to Amazon S3 using signed URLs with Node.js. So, here’s a rundown to avoid the same issues in the future.&lt;/p&gt;

&lt;p&gt;I referred to this article on generating signed URLs with Node.js:&lt;br&gt;
&lt;a href="https://qiita.com/l_v_yonsama/items/c7faa3fd7985bed75bcb" rel="noopener noreferrer"&gt;{AWS(CloudFront+S3)+Node.js} Delivering Private Content Using Signed URLs&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Successfully Generated Download Signed URLs
&lt;/h1&gt;

&lt;p&gt;Generating signed URLs for downloading worked smoothly with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// AWS authentication details&lt;/span&gt;

&lt;span class="c1"&gt;// Create S3 instance&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Generate download URL&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;downloadUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getObject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-bucket-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-object-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;Expires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Encountering Issues with Upload Signed URLs
&lt;/h1&gt;

&lt;p&gt;Using a similar approach, I generated upload signed URLs, which were created successfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// AWS authentication details&lt;/span&gt;

&lt;span class="c1"&gt;// Create S3 instance&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Generate upload URL&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uploadUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;putObject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-bucket-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-object-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;Expires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, when attempting to upload a file using the generated URL, I received a 403 status code. The response body looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Error&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Code&amp;gt;&lt;/span&gt;SignatureDoesNotMatch&lt;span class="nt"&gt;&amp;lt;/Code&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Message&amp;gt;&lt;/span&gt;The request signature we calculated does not match the signature you provided. Check your key and signing method.&lt;span class="nt"&gt;&amp;lt;/Message&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;AWSAccessKeyId&amp;gt;&lt;/span&gt;hoge&lt;span class="nt"&gt;&amp;lt;/AWSAccessKeyId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;StringToSign&amp;gt;&lt;/span&gt;hoge&lt;span class="nt"&gt;&amp;lt;/StringToSign&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;SignatureProvided&amp;gt;&lt;/span&gt;hoge&lt;span class="nt"&gt;&amp;lt;/SignatureProvided&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;StringToSignBytes&amp;gt;&lt;/span&gt;hoge&lt;span class="nt"&gt;&amp;lt;/StringToSignBytes&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;RequestId&amp;gt;&lt;/span&gt;hoge&lt;span class="nt"&gt;&amp;lt;/RequestId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;HostId&amp;gt;&lt;/span&gt;hoge&lt;span class="nt"&gt;&amp;lt;/HostId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Error&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short, it indicated an issue with the signing method.&lt;/p&gt;

&lt;h1&gt;
  
  
  Utilizing Signature Version 4
&lt;/h1&gt;

&lt;p&gt;After further investigation, I discovered an issue:&lt;br&gt;
&lt;a href="https://github.com/aws/aws-sdk-js/issues/902" rel="noopener noreferrer"&gt;Node.js pre-signed URL for PUT response is 'signature does not match'&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As per this issue, use signature version 4 when generating the URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create S3 instance&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;signatureVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Generate upload URL&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uploadUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSignedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;putObject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-bucket-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-object-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;Expires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By testing uploads with the above code, I successfully uploaded files!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I'm relieved to have resolved this issue. Special thanks to the following articles for their clear explanations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://qiita.com/l_v_yonsama/items/c7faa3fd7985bed75bcb" rel="noopener noreferrer"&gt;{AWS(CloudFront+S3)+Node.js} Delivering Private Content Using Signed URLs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/aws/aws-sdk-js/issues/902" rel="noopener noreferrer"&gt;Node.js pre-signed URL for PUT response is 'signature does not match'&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qiita.com/kyasbal_1994/items/774be5624e4d90c5cf38" rel="noopener noreferrer"&gt;Pitfalls of Using AWS-SDK's PreSigned URL for PUT in Node.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>aws</category>
    </item>
    <item>
      <title>Removing Only the First Line of a Multi-Line String in JavaScript</title>
      <dc:creator>Shoichi Okaniwa</dc:creator>
      <pubDate>Tue, 14 Apr 2026 15:18:22 +0000</pubDate>
      <link>https://dev.to/segur/removing-only-the-first-line-of-a-multi-line-string-in-javascript-29jd</link>
      <guid>https://dev.to/segur/removing-only-the-first-line-of-a-multi-line-string-in-javascript-29jd</guid>
      <description>&lt;h1&gt;
  
  
  Encountering a CSV File with an Unusual First Line
&lt;/h1&gt;

&lt;p&gt;I came across a CSV file like the one below. (This is not actual business data.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hogehoge
name,value,count
りんご,100,2
バナナ,150,4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this scenario, there's an unwanted string in the first line that isn't in CSV format. I needed to remove it before processing the CSV data. Let's assume the line breaks are &lt;code&gt;LF&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Removing Only the First Line of a Multi-Line String
&lt;/h1&gt;

&lt;p&gt;Surprisingly, I couldn't find many articles on this topic, so I'm documenting it before I forget.&lt;/p&gt;

&lt;p&gt;This can be achieved with a combination of &lt;code&gt;indexOf&lt;/code&gt; and &lt;code&gt;substr&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Define a multi-line string (In reality, this would be read from a file)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`hogehoge
name,value,count
りんご,100,2
バナナ,150,4`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Find the position of the first line break&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstRowEndPos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inputString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Extract the string starting from the position after the first line break&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outputString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inputString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firstRowEndPos&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Display the result&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outputString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  In Conclusion
&lt;/h1&gt;

&lt;p&gt;It was relatively simple to implement. If you also need to consider &lt;code&gt;CR&lt;/code&gt;, it might become a bit more complex.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Copy Firebase Environment Variables to Bash</title>
      <dc:creator>Shoichi Okaniwa</dc:creator>
      <pubDate>Mon, 13 Apr 2026 15:21:07 +0000</pubDate>
      <link>https://dev.to/segur/copy-firebase-environment-variables-to-bash-1pbb</link>
      <guid>https://dev.to/segur/copy-firebase-environment-variables-to-bash-1pbb</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Firebase functions allow you to set environment variables. For an easy-to-understand guide on setting them, please refer to this article: &lt;a href="https://qiita.com/nerdyboy_cool/items/695c8af7ca8d22761927" rel="noopener noreferrer"&gt;How to Set Environment Variables in Firebase&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I wanted to use these environment variables in Bash as well, so I devised a command to copy them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example of Environment Variables
&lt;/h2&gt;

&lt;p&gt;Assume the following environment variables are registered in Firebase functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hoge"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"client_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fuga"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"client_secret"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"piyo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal here is to copy the &lt;code&gt;client_id&lt;/code&gt; and &lt;code&gt;client_secret&lt;/code&gt; into Bash.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing jq
&lt;/h2&gt;

&lt;p&gt;To parse JSON, we need the command-line tool &lt;code&gt;jq&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Mac&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;jq

&lt;span class="c"&gt;# Windows&lt;/span&gt;
choco &lt;span class="nb"&gt;install &lt;/span&gt;jq

&lt;span class="c"&gt;# Ubuntu&lt;/span&gt;
apt-get &lt;span class="nb"&gt;install &lt;/span&gt;jq

&lt;span class="c"&gt;# CentOS&lt;/span&gt;
yum &lt;span class="nb"&gt;install &lt;/span&gt;jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Registering in Bash Environment Variables
&lt;/h2&gt;

&lt;p&gt;You can register them with the following command:&lt;br&gt;
&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;export&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;firebase functions:config:get | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.hoge'&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'keys[] as $k | "export \($k)=\(.[$k])"'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;hoge&lt;/code&gt; with the appropriate value as needed.&lt;/p&gt;

&lt;p&gt;This method was inspired by the article &lt;a href="https://qiita.com/arc279/items/3e88bc668987927c03d6" rel="noopener noreferrer"&gt;Export JSON key:value to environment variables&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying Bash Environment Variables
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;client_id&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
fuga

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;client_secret&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
piyo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variables were successfully copied.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The following articles were invaluable references. Thank you for the clear guidance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://qiita.com/nerdyboy_cool/items/695c8af7ca8d22761927" rel="noopener noreferrer"&gt;How to Set Environment Variables in Firebase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qiita.com/arc279/items/3e88bc668987927c03d6" rel="noopener noreferrer"&gt;Export JSON key:value to environment variables&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bash</category>
      <category>firebase</category>
      <category>json</category>
    </item>
    <item>
      <title>IoT Setup in My Home</title>
      <dc:creator>Shoichi Okaniwa</dc:creator>
      <pubDate>Sun, 12 Apr 2026 14:46:55 +0000</pubDate>
      <link>https://dev.to/segur/iot-setup-in-my-home-3ie6</link>
      <guid>https://dev.to/segur/iot-setup-in-my-home-3ie6</guid>
      <description>&lt;h1&gt;
  
  
  IoT Setup in My Home
&lt;/h1&gt;

&lt;p&gt;I often get asked about the configuration of IoT devices in my home, so I've created a diagram to illustrate it.&lt;/p&gt;

&lt;p&gt;The diagram shows two instances of Wi-Fi, though they represent the same device. I structured it this way to depict the flow of data from left to right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsy5t0rdx62hlvq1b8zbr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsy5t0rdx62hlvq1b8zbr.png" alt="image.png" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Nature Remo
&lt;/h1&gt;

&lt;p&gt;Thanks to Nature Remo, I can control devices like projectors and air conditioners that are not IoT-compatible via infrared. I highly recommend it!&lt;/p&gt;

&lt;h1&gt;
  
  
  IFTTT
&lt;/h1&gt;

&lt;p&gt;Most IoT products come with their own smartphone apps for precise control. However, to manage multiple IoT products collectively, I've consolidated all controls using IFTTT.&lt;/p&gt;

&lt;p&gt;By setting up scenarios like leaving home, returning home, or bedtime within IFTTT, and registering the control actions for various IoT products there, it becomes incredibly convenient.&lt;/p&gt;

</description>
      <category>iot</category>
      <category>smarthome</category>
      <category>automation</category>
      <category>integration</category>
    </item>
    <item>
      <title>Voice Chat on Discord with VOICEROID Transformed Speech</title>
      <dc:creator>Shoichi Okaniwa</dc:creator>
      <pubDate>Sat, 11 Apr 2026 14:41:16 +0000</pubDate>
      <link>https://dev.to/segur/voice-chat-on-discord-with-voiceroid-transformed-speech-4201</link>
      <guid>https://dev.to/segur/voice-chat-on-discord-with-voiceroid-transformed-speech-4201</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;I experimented with converting my voice using VOICEROID while chatting on Discord. Initially, I couldn't hear the transformed voice myself, so I researched how to enable this. I hope this is helpful for those starting as machine-voiced VTubers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setup Overview
&lt;/h1&gt;

&lt;p&gt;The setup process involves the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Record your voice via a microphone&lt;/li&gt;
&lt;li&gt;Convert the voice to text using Yukari-net&lt;/li&gt;
&lt;li&gt;Use VOICEROID to generate audio from the text&lt;/li&gt;
&lt;li&gt;Input the audio into VB-AUDIO&lt;/li&gt;
&lt;li&gt;Set this as the input device on Discord&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Preparations
&lt;/h1&gt;

&lt;p&gt;It's assumed that you have set up the flow from Microphone to Yukari-net to VOICEROID.&lt;/p&gt;

&lt;p&gt;This article was extremely helpful:&lt;br&gt;&lt;br&gt;
&lt;a href="https://ariemonn.net/entry/2018/01/22/131410" rel="noopener noreferrer"&gt;https://ariemonn.net/entry/2018/01/22/131410&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Installing Virtual Audio Device
&lt;/h1&gt;

&lt;p&gt;Install the virtual audio device &lt;strong&gt;VB-CABLE&lt;/strong&gt; from:&lt;br&gt;&lt;br&gt;
&lt;a href="https://www.vb-audio.com/Cable/" rel="noopener noreferrer"&gt;https://www.vb-audio.com/Cable/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This guide was beneficial:&lt;br&gt;&lt;br&gt;
&lt;a href="https://arutora.com/archives/20180516223000/" rel="noopener noreferrer"&gt;https://arutora.com/archives/20180516223000/&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Configuring Virtual Audio Device
&lt;/h1&gt;

&lt;p&gt;Next, in VOICEROID, go to &lt;code&gt;Options&lt;/code&gt; → &lt;code&gt;Others&lt;/code&gt; → &lt;code&gt;Audio Device&lt;/code&gt; and select &lt;code&gt;CABLE Input (VB-Audio Virtual Cable)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl1kiemwd9om3lcxq6635.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl1kiemwd9om3lcxq6635.png" alt="image.png" width="530" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, in Discord, click the gear icon → &lt;code&gt;App Settings&lt;/code&gt; → &lt;code&gt;Voice &amp;amp; Video&lt;/code&gt; → &lt;code&gt;Input Device&lt;/code&gt; and choose &lt;code&gt;CABLE Output (VB-Audio Virtual Cable)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fczwwu7f5gwsi1yrc4z5d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fczwwu7f5gwsi1yrc4z5d.png" alt="image.png" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows you to converse with the VOICEROID voice on Discord. However, you still can't hear the transformed voice yourself yet.&lt;/p&gt;

&lt;h1&gt;
  
  
  Listening to Your Transformed Voice
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzqpyqcgyr3fjhxx41h7n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzqpyqcgyr3fjhxx41h7n.png" alt="image.png" width="352" height="39"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Windows 10, right-click the &lt;strong&gt;speaker icon&lt;/strong&gt; 🔈 in the notification area (task tray) → &lt;code&gt;Sound&lt;/code&gt; → &lt;code&gt;Recording&lt;/code&gt; tab → right-click on &lt;code&gt;CABLE Output&lt;/code&gt; → &lt;code&gt;Properties&lt;/code&gt; → &lt;code&gt;Listen&lt;/code&gt; tab → check &lt;code&gt;Listen to this device&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eqit0arcrxlq3b6vfzo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3eqit0arcrxlq3b6vfzo.png" alt="image.png" width="465" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you can hear the transformed voice.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;By substituting the Discord setting with VRChat, you can also converse in VR worlds!&lt;/p&gt;

</description>
      <category>discord</category>
      <category>vtuber</category>
      <category>voiceroid</category>
    </item>
  </channel>
</rss>
