<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
	<channel>
		<title>Angel's Blog</title>
		<link>https://angelcool.net/sphpblog/blog_index.php</link>
		<description><![CDATA[No Footer]]></description>
		<copyright>Copyright 2026, Angel</copyright>
		<managingEditor>Angel</managingEditor>
		<language>en-US</language>
		<generator>SPHPBLOG 0.7.0</generator>
		<item>
			<title>JAVA: Initializing Spring Boot Application</title>
			<link>https://angelcool.net/sphpblog/blog_index.php?entry=entry250602-032204</link>
			<description><![CDATA[<pre>angelcool@lolcahost:~/code-learning/Java/spring-boot$ date<br />Sun Jun  1 12:30:32 PM PDT 2025<br />angelcool@lolcahost:~/code-learning/Java/spring-boot$ pwd<br />/home/angelcool/code-learning/Java/spring-boot<br /><br /># INITIALIZE APPLICATION<br />angelcool@lolcahost:~/code-learning/Java/spring-boot$ spring init -a my-demo -l java --build maven -x my-demo<br />Using service at <a href="https://start.spring.io" >https://start.spring.io</a><br />Project extracted to &#039;/home/angelcool/code-learning/Java/spring-boot/my-demo&#039;<br />angelcool@lolcahost:~/code-learning/Java/spring-boot$<br /><br /># INSTALL MAVEN<br />angelcool@localhost:~/code-learning/Java/spring-boot/my-demo$ sudo dnf install maven<br />...<br />angelcool@localhost:~/code-learning/Java/spring-boot/my-demo$ mvn --version<br />Apache Maven 3.9.6 (Red Hat 3.9.6-7)<br />...<br /><br /># RUN APPLICATION, NOTE: I think I had to update the artifactId in pom.xml to &#039;spring-boot-starter-web&#039;<br />angelcool@localhost:~/code-learning/Java/spring-boot/my-demo$ mvn spring-boot:run<br />...<br /><br /># MAKE REQUEST<br />angelcool@localhost:~/code-learning/Java/spring-boot/my-demo$ http  <a href="http://localhost:8080/coffees" >http://localhost:8080/coffees</a><br />HTTP/1.1 200 <br />Connection: keep-alive<br />Content-Type: application/json<br />Date: Mon, 02 Jun 2025 03:13:46 GMT<br />Keep-Alive: timeout=60<br />Transfer-Encoding: chunked<br /><br />[<br />    {<br />        &quot;id&quot;: &quot;3d1256a7-c5c8-4a9b-9ef3-60da3107b06b&quot;,<br />        &quot;name&quot;: &quot;Black&quot;<br />    },<br />    {<br />        &quot;id&quot;: &quot;7fc475b2-7c39-4412-baeb-6ac01f46128c&quot;,<br />        &quot;name&quot;: &quot;French Vanilla&quot;<br />    },<br />    {<br />        &quot;id&quot;: &quot;690c16af-3931-4dbd-b573-a9d8c86e0a3c&quot;,<br />        &quot;name&quot;: &quot;Hazelnut&quot;<br />    }<br />]<br /><br /># SOURCE CODE<br />angelcool@localhost:~/code-learning/Java/spring-boot/my-demo$ cat src/main/java/com/example/my_demo/DemoApplication.java <br />package com.example.my_demo;<br /><br />import org.springframework.boot.SpringApplication;<br />import org.springframework.boot.autoconfigure.SpringBootApplication;<br />// import org.springframework.stereotype.Controller;<br />import org.springframework.web.bind.annotation.RequestMapping;<br />// import org.springframework.web.bind.annotation.ResponseBody;<br />import org.springframework.web.bind.annotation.RestController;<br />// import org.springframework.ui.Model;<br />import java.util.ArrayList;<br />import java.util.List;<br />import org.springframework.web.bind.annotation.RequestMethod;<br />import java.util.UUID;<br /><br />@SpringBootApplication<br />public class DemoApplication {<br /><br />	public static void main(String[] args) {<br />		SpringApplication.run(DemoApplication.class, args);<br />	}<br />}<br /><br />class Coffee {<br />	private final String id;<br />	private String name;<br /><br />	public Coffee(String id, String name) {<br />		this.id = id;<br />		this.name = name;<br />	}<br /><br />	public Coffee (String name) {<br />		this(UUID.randomUUID().toString(),name);<br />	}<br /><br />	public String getId(){<br />		return this.id;<br />	}<br /><br />	public String getName(){<br />		return this.name;<br />	}<br /><br />	public void setName(String name){<br />		this.name = name;<br />	}<br />}<br /><br />@RestController<br />class RestApiController{<br />	private List&lt;Coffee&gt; coffees = new ArrayList&lt;&gt;();<br /><br />	public RestApiController(){<br />		this.coffees.addAll(List.of(<br />			new Coffee(&quot;Black&quot;),<br />			new Coffee(&quot;French Vanilla&quot;),<br />			new Coffee(&quot;Hazelnut&quot;)<br />		));<br />	}<br /><br />	@RequestMapping(value = &quot;/coffees&quot;, method = RequestMethod.GET)<br />	Iterable&lt;Coffee&gt; getCoffees() {<br />		return this.coffees;<br />	}<br />}<br /></pre>]]></description>
			<category>- Java Notes</category>
			<guid isPermaLink="true">https://angelcool.net/sphpblog/blog_index.php?entry=entry250602-032204</guid>
			<author>Angel</author>
			<pubDate>Mon, 02 Jun 2025 03:22:04 GMT</pubDate>
		</item>
		<item>
			<title>Java: Installing Spring Boot CLI</title>
			<link>https://angelcool.net/sphpblog/blog_index.php?entry=entry250601-000603</link>
			<description><![CDATA[<pre>angelcool@localhost:~$<br />angelcool@localhost:~$ date<br />Sat May 31 04:57:16 PM PDT 2025<br />angelcool@localhost:~$ cat /etc/redhat-release <br />Fedora release 41 (Forty One)<br />angelcool@localhost:~$ <br /># INSTALL SDKMAN<br />angelcool@localhost:~$ curl -s &quot;https://get.sdkman.io&quot; | bash<br />...<br /># CHECK SDKMAN VERSION<br />angelcool@localhost:~$ sdk version<br /><br />SDKMAN!<br />script: 5.19.0<br />native: 0.7.4 (linux x86_64)<br /><br /># INSTALL SPRING BOOT CLI<br />angelcool@localhost:~$ sdk install springboot<br />...<br /># CHECK SPRING BOOT CLI VERSION<br />angelcool@localhost:~$ spring --version<br />Spring CLI v3.5.0<br />angelcool@localhost:~$<br />angelcool@localhost:~$<br /></pre>]]></description>
			<category>- Java Notes</category>
			<guid isPermaLink="true">https://angelcool.net/sphpblog/blog_index.php?entry=entry250601-000603</guid>
			<author>Angel</author>
			<pubDate>Sun, 01 Jun 2025 00:06:03 GMT</pubDate>
		</item>
		<item>
			<title>Using GNU comm to compare sorted files line by line. </title>
			<link>https://angelcool.net/sphpblog/blog_index.php?entry=entry241218-034133</link>
			<description><![CDATA[This is similar to PHP&#039;s array_diff and Java&#039;s removeAll(). Helpful in finding diffs between lists of ids.<br /><br /><pre>angelcool@fedora-laptop$cat FILE1.txt <br />1<br />2<br />3<br />4<br />5<br />5<br />angelcool@fedora-laptop$cat FILE2.txt <br />1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />angelcool@fedora-laptop$comm -13 &lt;(sort FILE1.txt|uniq) &lt;(sort FILE2.txt|uniq)<br />6<br />7<br />8<br />9<br />angelcool@fedora-laptop$ man comm<br />...<br />       Compare sorted files FILE1 and FILE2 line by line.<br /><br />       When FILE1 or FILE2 (not both) is -, read standard input.<br /><br />       With  no  options,  produce three-column output.  Column one contains lines unique to FILE1, column two con‐<br />       tains lines unique to FILE2, and column three contains lines common to both files.<br /><br />       -1     suppress column 1 (lines unique to FILE1)<br /><br />       -2     suppress column 2 (lines unique to FILE2)<br /><br />       -3     suppress column 3 (lines that appear in both files)<br /><br />       --check-order<br />              check that the input is correctly sorted, even if all input lines are pairable<br /><br />       --nocheck-order<br />              do not check that the input is correctly sorted<br /><br />       --output-delimiter=STR<br />              separate columns with STR<br /><br />       --total<br />              output a summary<br /><br />       -z, --zero-terminated<br />              line delimiter is NUL, not newline<br /><br />       --help display this help and exit<br /><br />       --version<br />              output version information and exit<br /><br />       Note, comparisons honor the rules specified by &#039;LC_COLLATE&#039;.<br />...</pre>]]></description>
			<category>- Bash Notes</category>
			<guid isPermaLink="true">https://angelcool.net/sphpblog/blog_index.php?entry=entry241218-034133</guid>
			<author>Angel</author>
			<pubDate>Wed, 18 Dec 2024 03:41:33 GMT</pubDate>
		</item>
		<item>
			<title>Java: My First Servlet</title>
			<link>https://angelcool.net/sphpblog/blog_index.php?entry=entry241124-015310</link>
			<description><![CDATA[<pre>angelcool@fedora-laptop$date<br />Sat Nov 23 05:57:16 PM PST 2024<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$java --version<br />openjdk 17.0.13 2024-10-15<br />OpenJDK Runtime Environment (Red_Hat-17.0.13.0.11-1) (build 17.0.13+11)<br />OpenJDK 64-Bit Server VM (Red_Hat-17.0.13.0.11-1) (build 17.0.13+11, mixed mode, sharing)<br />angelcool@fedora-laptop$jar --version<br />jar 17.0.13<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$pwd<br />/home/angelcool/java-practice/HelloWorldServlet<br />angelcool@fedora-laptop$tree<br />.<br />├── deploy<br />│   └── helloworld.war<br />├── Notes.txt<br />├── src<br />│   ├── HelloWorld.class<br />│   └── HelloWorld.java<br />└── web<br />    └── WEB-INF<br />        ├── classes<br />        │   └── com<br />        │       └── coolwriter<br />        │           └── helloworld<br />        │               └── HelloWorld.class<br />        └── web.xml<br /><br />9 directories, 6 files<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$cat Notes.txt <br /># Compile java class, this will create HelloWorld.class<br />angelcool@fedora-laptop$javac --class-path /usr/share/tomcat/lib/tomcat-servlet-api.jar src/HelloWorld.java<br /><br /># Copy compiled .class file to WEB-INF <br />angelcool@fedora-laptop$cp src/HelloWorld.class web/WEB-INF/classes/com/coolwriter/helloworld/<br /><br /># Create WAR file<br />angelcool@fedora-laptop$jar cvf deploy/helloworld.war -C web .<br /><br /># Move WAR file to Tomcat webapps directory<br />angelcool@fedora-laptop$sudo  cp deploy/helloworld.war /usr/share/tomcat/webapps/<br /><br /># Reload servlet in /manager page ( or restart Tomcat I think )<br /><br /># Access servlet: <a href="http://localhost:8080/helloworld/Hello" >http://localhost:8080/helloworld/Hello</a><br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$cat web/WEB-INF/web.xml <br />&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br />&lt;web-app version=&quot;4.0&quot; xmlns=&quot;http://xmlns.jcp.org/xml/ns/javaee&quot;<br />   xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;<br />   xsi:schemaLocation=&quot;http://xmlns.jcp.org/xml/ns/javaee <br />   <a href="http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd&quot;&gt;" >http://xmlns.jcp.org/xml/ns/javaee/web- ... &quot;&gt;</a><br /><br />  &lt;display-name&gt;Hello World!&lt;/display-name&gt;<br /><br />  &lt;servlet&gt;<br />    &lt;servlet-name&gt;helloworld&lt;/servlet-name&gt;<br />    &lt;servlet-class&gt;com.coolwriter.helloworld.HelloWorld&lt;/servlet-class&gt;<br />  &lt;/servlet&gt;<br /><br />  &lt;servlet-mapping&gt;<br />    &lt;servlet-name&gt;helloworld&lt;/servlet-name&gt;<br />    &lt;url-pattern&gt;/Hello&lt;/url-pattern&gt;<br />  &lt;/servlet-mapping&gt;<br /><br />&lt;/web-app&gt;<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$cat src/HelloWorld.java <br />package com.coolwriter.helloworld;<br /><br />import java.io.*;<br />import javax.servlet.*;<br />import javax.servlet.http.*;<br />import java.util.*;<br /><br />public class HelloWorld extends HttpServlet<br />{<br />    public void doGet(HttpServletRequest request, HttpServletResponse response)<br />        throws IOException, ServletException<br />    {<br />        response.setContentType(&quot;text/html&quot;);<br /><br />        PrintWriter out = response.getWriter();<br />        <br />        String msg = this.getGreeting();<br /><br />        out.println(msg);<br />    }<br /><br />    private String getGreeting()<br />    {<br />        String msg = null;<br /><br />        int rand = (int) (Math.random() * (6)) +1;<br /><br />        switch (rand) {<br />        case 1:<br />            msg = &quot;Hello There!&quot;;<br />            break;<br />        case 2:<br />            msg = &quot;Hello Friend!&quot;;<br />            break;<br />        case 3:<br />            msg = &quot;Hello Stranger!&quot;;<br />            break;<br />        case 4:<br />            msg = &quot;Hello! My name is Angel!&quot;;<br />            break;<br />        default:<br />            msg = &quot;Hello World!&quot;;<br />        }<br /><br />        return msg;<br />    }<br />}<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$<br /></pre>]]></description>
			<category>- Java Notes</category>
			<guid isPermaLink="true">https://angelcool.net/sphpblog/blog_index.php?entry=entry241124-015310</guid>
			<author>Angel</author>
			<pubDate>Sun, 24 Nov 2024 01:53:10 GMT</pubDate>
		</item>
		<item>
			<title>Java: Installing Tomcat in Fedora 39</title>
			<link>https://angelcool.net/sphpblog/blog_index.php?entry=entry241123-202018</link>
			<description><![CDATA[<pre>angelcool@fedora-laptop$date<br />Sat Nov 23 12:00:14 PM PST 2024<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$cat /etc/redhat-release <br />Fedora release 39 (Thirty Nine)<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$dnf info tomcat<br />Last metadata expiration check: 0:42:59 ago on Sat 23 Nov 2024 11:18:54 AM PST.<br />Installed Packages<br />Name         : tomcat<br />Epoch        : 1<br />Version      : 9.0.96<br />Release      : 1.fc39<br />Architecture : noarch<br />Size         : 323 k<br />Source       : tomcat-9.0.96-1.fc39.src.rpm<br />Repository   : @System<br />From repo    : updates<br />Summary      : Apache Servlet/JSP Engine, RI for Servlet 4.0/JSP 2.3 API<br />URL          : <a href="http://tomcat.apache.org/" >http://tomcat.apache.org/</a><br />License      : ASL 2.0<br />Description  : Tomcat is the servlet container that is used in the official Reference<br />             : Implementation for the Java Servlet and JavaServer Pages technologies.<br />             : The Java Servlet and JavaServer Pages specifications are developed by<br />             : Sun under the Java Community Process.<br />             : <br />             : Tomcat is developed in an open and participatory environment and<br />             : released under the Apache Software License version 2.0. Tomcat is intended<br />             : to be a collaboration of the best-of-breed developers from around the world.<br /><br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$sudo dnf install tomcat<br />...<br />angelcool@fedora-laptop$sudo dnf install tomcat-admin-webapps<br />...<br />angelcool@fedora-laptop$sudo dnf install tomcat-docs-webapp<br />...<br />angelcool@fedora-laptop$sudo systemctl start tomcat.service<br />...</pre><br /><br />Enable admin user, uncomment the following in /etc/tomcat/tomcat-users.xml<br /><pre>&lt;role rolename=&quot;admin&quot;/&gt;<br />&lt;role rolename=&quot;admin-gui&quot;/&gt;<br />&lt;role rolename=&quot;admin-script&quot;/&gt;<br />&lt;role rolename=&quot;manager&quot;/&gt;<br />&lt;role rolename=&quot;manager-gui&quot;/&gt;<br />&lt;role rolename=&quot;manager-script&quot;/&gt;<br />&lt;role rolename=&quot;manager-jmx&quot;/&gt;<br />&lt;role rolename=&quot;manager-status&quot;/&gt;<br />&lt;user name=&quot;admin&quot; password=&quot;admin&quot; roles=&quot;admin,manager,admin-gui,admin-script,manager-gui,manager-script,manager-jmx,manager-status&quot; /&gt;</pre><br /><br />Restart server and go to: <a href="http://localhost:8080/manager/html" >http://localhost:8080/manager/html</a><br /><br />For reference:<br /><pre>angelcool@fedora-laptop$<br />angelcool@fedora-laptop$tree /usr/share/tomcat/webapps/<br />/usr/share/tomcat/webapps/<br />├── host-manager<br />│   ├── css<br />│   │   └── manager.css<br />│   ├── images<br />│   │   ├── asf-logo.svg<br />│   │   └── tomcat.svg<br />│   ├── index.jsp<br />│   ├── META-INF<br />│   │   └── context.xml<br />│   └── WEB-INF<br />│       ├── jsp<br />│       │   ├── 401.jsp<br />│       │   ├── 403.jsp<br />│       │   └── 404.jsp<br />│       ├── manager.xml<br />│       └── web.xml<br />└── manager<br />    ├── css<br />    │   └── manager.css<br />    ├── images<br />    │   ├── asf-logo.svg<br />    │   └── tomcat.svg<br />    ├── index.jsp<br />    ├── META-INF<br />    │   └── context.xml<br />    ├── status.xsd<br />    ├── WEB-INF<br />    │   ├── jsp<br />    │   │   ├── 401.jsp<br />    │   │   ├── 403.jsp<br />    │   │   ├── 404.jsp<br />    │   │   ├── connectorCerts.jsp<br />    │   │   ├── connectorCiphers.jsp<br />    │   │   ├── connectorTrustedCerts.jsp<br />    │   │   ├── sessionDetail.jsp<br />    │   │   └── sessionsList.jsp<br />    │   └── web.xml<br />    └── xform.xsl<br /><br />13 directories, 26 files<br />angelcool@fedora-laptop$</pre>]]></description>
			<category>- Java Notes</category>
			<guid isPermaLink="true">https://angelcool.net/sphpblog/blog_index.php?entry=entry241123-202018</guid>
			<author>Angel</author>
			<pubDate>Sat, 23 Nov 2024 20:20:18 GMT</pubDate>
		</item>
		<item>
			<title>Miscellaneous Notes</title>
			<link>https://angelcool.net/sphpblog/blog_index.php?entry=entry240706-235032</link>
			<description><![CDATA[Miscellaneous notes for troubleshooting, gathering information about a redis/valkey setup, etc.<br /><br /><pre>acool@acool-HP-EliteBook-8440p:~/redis-cluster$ date<br />Sat 06 Jul 2024 04:44:24 PM PDT<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ redis-cli --version<br />redis-cli 5.0.7<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ ### Find out node&#039;s role<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ redis-cli -c -p 7000 INFO|grep role<br />role:master<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ ### If node is master...<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ redis-cli -c -p 7000 INFO|grep slave0<br />slave0:ip=127.0.0.1,port=7005,state=online,offset=7532,lag=0<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ <br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ ### Verify this node is slave...<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ redis-cli -c -p 7005 INFO|grep role<br />role:slave<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ ### Find out node&#039;s master...<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ redis-cli -c -p 7005 INFO | egrep &quot;master_(host|port)&quot;<br />master_host:127.0.0.1<br />master_port:7000<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ ### Find out node&#039;s mode...<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ redis-cli -c -p 7003 INFO | egrep mode<br />redis_mode:cluster<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$  ###  List all cluster nodes<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ redis-cli -c -p 7004 CLUSTER NODES<br />99f95692421cd04661c93ef9f09e058a7a80a6e4 127.0.0.1:7002@17002 master - 0 1720310325000 3 connected 10923-16383<br />8589237392750f2df8618bcda4e92e3996dda07a 127.0.0.1:7005@17005 slave 02c090059770ba140c14a1f26a16b3457fd58bf1 0 1720310324000 6 connected<br />c53fa6a32d9646c21549346716f01a5147cb8bb9 127.0.0.1:7001@17001 master - 0 1720310325468 2 connected 5461-10922<br />02c090059770ba140c14a1f26a16b3457fd58bf1 127.0.0.1:7000@17000 master - 0 1720310325000 1 connected 0-5460<br />ed206ea99f372d34dee37433b7747b5f2b2a3a40 127.0.0.1:7003@17003 slave c53fa6a32d9646c21549346716f01a5147cb8bb9 0 1720310325567 4 connected<br />05fe8b609e4b13d0510ed9b32b27b84502898595 127.0.0.1:7004@17004 myself,slave 99f95692421cd04661c93ef9f09e058a7a80a6e4 0 1720310323000 5 connected<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ ### This command seems to run INFO in all cluster nodes...                <br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ redis-cli --cluster call 127.0.0.1:7000 INFO|grep role<br />role:master<br />role:master<br />role:slave<br />role:slave<br />role:slave<br />role:master<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ ### monitor node<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ redis-cli -c -p 7005 monitor<br />...<br /></pre><br />Find out data directory and config path:<br /><pre>acool@acool-HP-EliteBook-8440p:~/redis-cluster$ ####### FIND PATH for rdb AND aof FILES!!!! #######<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ <br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ <br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ redis-cli -c -p 7000 CONFIG GET dir<br />1) &quot;dir&quot;<br />2) &quot;/home/acool/redis-cluster/7000&quot;<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ <br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ <br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ <br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ <br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ redis-cli --cluster call 127.0.0.1:7000 CONFIG GET dir<br />&gt;&gt;&gt; Calling CONFIG GET dir<br />127.0.0.1:7000: dir<br />/home/acool/redis-cluster/7000<br />127.0.0.1:7001: dir<br />/home/acool/redis-cluster/7001<br />127.0.0.1:7004: dir<br />/home/acool/redis-cluster/7004<br />127.0.0.1:7005: dir<br />/home/acool/redis-cluster/7005<br />127.0.0.1:7003: dir<br />/home/acool/redis-cluster/7003<br />127.0.0.1:7002: dir<br />/home/acool/redis-cluster/7002<br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ <br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ <br />acool@acool-HP-EliteBook-8440p:~/redis-cluster$ redis-cli --cluster call 127.0.0.1:7000 INFO | grep -i config_file<br />...<br /></pre>]]></description>
			<category>- Redis Notes</category>
			<guid isPermaLink="true">https://angelcool.net/sphpblog/blog_index.php?entry=entry240706-235032</guid>
			<author>Angel</author>
			<pubDate>Sat, 06 Jul 2024 23:50:32 GMT</pubDate>
		</item>
		<item>
			<title>Valkey Cluster Demo</title>
			<link>https://angelcool.net/sphpblog/blog_index.php?entry=entry240705-213550</link>
			<description><![CDATA[<pre>[acool@localhost ~]$ date<br />Fri Jul  5 01:48:53 PM PDT 2024<br />[acool@localhost ~]$ cat /etc/redhat-release <br />Fedora release 38 (Thirty Eight)<br />[acool@localhost ~]$ sudo dnf install valkey<br />...<br />[acool@localhost ~]$ valkey-cli --version<br />valkey-cli 7.2.4<br />[acool@localhost ~]$<br />[acool@localhost ~]$ # just in case...<br />[acool@localhost ~]$ systemctl stop valkey.service<br />[acool@localhost ~]$ systemctl status valkey.service<br />...<br />[acool@localhost ~]$ which valkey-server<br />/usr/bin/valkey-server<br />[acool@localhost ~]$<br />[acool@localhost ~]$ mkdir valkey-cluster-demo<br />[acool@localhost ~]$ cd valkey-cluster-demo/<br />[acool@localhost valkey-cluster-demo]$ vim valkey.conf<br />...<br />[acool@localhost valkey-cluster-demo]$ cat valkey.conf<br />port 7000<br />cluster-enabled yes<br />cluster-config-file nodes.conf<br />cluster-node-timeout 5000<br />appendonly yes<br />[acool@localhost valkey-cluster-demo]$<br />[acool@localhost valkey-cluster-demo]$ mkdir cluster-test<br />[acool@localhost valkey-cluster-demo]$ cd cluster-test/<br />[acool@localhost cluster-test]$ mkdir -p {7000..7005}<br />[acool@localhost cluster-test]$ for i in {7000..7005}; do cp ../valkey.conf $i; done<br />[acool@localhost cluster-test]$ # open 7 tabs, update ports and start servers<br />[acool@localhost cluster-test]$ # TIP to update ports: for i in {0..5}; do  sed -i &#039;s/7000/700&#039;&quot;$i&quot;&#039;/g&#039;  &quot;700$i/redis.conf&quot; ; done<br />[acool@localhost cluster-test]$ cd 7000/<br />[acool@localhost 7000]$ /usr/bin/valkey-server ./valkey.conf<br />...<br />[acool@localhost valkey-cluster-demo] # create cluster<br />[acool@localhost valkey-cluster-demo]$ valkey-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1<br />...<br />[acool@localhost valkey-cluster-demo]$ valkey-cli -p 7000 cluster nodes<br />384d585df521f8588a03b57a38e871549c0e58c4 127.0.0.1:7001@17001 master - 0 1720214911355 2 connected 5461-10922<br />5d2edcbba8f394a612df5253bd19a9399f97f4ff 127.0.0.1:7002@17002 master - 0 1720214912358 3 connected 10923-16383<br />4cf4150f20ae444422f0dabbc29b0a75878b1a2d 127.0.0.1:7004@17004 slave c88d6bea070f64023a2c7f27831bbbd113b2ff03 0 1720214912000 1 connected<br />e40a58e318f277ce2d420f7cb77480d5643c28c4 127.0.0.1:7005@17005 slave 384d585df521f8588a03b57a38e871549c0e58c4 0 1720214913362 2 connected<br />c88d6bea070f64023a2c7f27831bbbd113b2ff03 127.0.0.1:7000@17000 myself,master - 0 1720214912000 1 connected 0-5460<br />5b13cd8e34b47890e88fb48e30a99174ba19b751 127.0.0.1:7003@17003 slave 5d2edcbba8f394a612df5253bd19a9399f97f4ff 0 1720214911354 3 connected<br />[acool@localhost valkey-cluster-demo]$<br />[acool@localhost valkey-cluster-demo]$<br />[acool@localhost valkey-cluster-demo]$ # To connect to Valkey Cluster, you&#039;ll need a cluster-aware Valkey client...<br />[acool@localhost valkey-cluster-demo]$ # ...store some keys<br />[acool@localhost valkey-cluster-demo]$ valkey-cli -c -p 7000<br />127.0.0.1:7000&gt; set firstname Angel<br />-&gt; Redirected to slot [7108] located at 127.0.0.1:7001<br />OK<br />127.0.0.1:7001&gt; set lastname Cool<br />OK<br />127.0.0.1:7001&gt;exit<br />[acool@localhost valkey-cluster-demo]$<br />[acool@localhost valkey-cluster-demo]$ # Retrive some keys<br />[acool@localhost valkey-cluster-demo]$ valkey-cli -c -p 7005<br />127.0.0.1:7005&gt; get lastname<br />-&gt; Redirected to slot [7726] located at 127.0.0.1:7001<br />&quot;Cool&quot;<br />127.0.0.1:7001&gt; get firstname<br />&quot;Angel&quot;<br />127.0.0.1:7001&gt;exit<br />[acool@localhost valkey-cluster-demo]$<br />[acool@localhost valkey-cluster-demo]$</pre><br /><br />TIP: Easy way to start all servers:<br /><pre>acool@acool-HP-EliteBook-8440p:~/redis-cluster$ for i in {0..5}; do  cd /home/acool/redis-cluster/700$i &amp;&amp; /usr/bin/redis-server redis.conf --daemonize yes; done</pre><br /><br />Bonus: Pub/Sub demo<br /><br /><pre>[acool@localhost valkey-cluster-demo]$ # TERMINAL 1<br />[acool@localhost valkey-cluster-demo]$ valkey-cli -c -p 7001<br />127.0.0.1:7001&gt; SUBSCRIBE channel-a<br />...<br />[acool@localhost valkey-cluster-demo]$ # TERMINAL 2<br />[acool@localhost valkey-cluster-demo]$ valkey-cli -c -p 7002<br />127.0.0.1:7002&gt; SUBSCRIBE channel-b<br />...<br /><br />[acool@localhost valkey-cluster-demo]$ # TERMINAL 3<br />[acool@localhost valkey-cluster-demo]$ valkey-cli -c -p 7000<br />127.0.0.1:7000&gt; PUBLISH channel-a &quot;Hello channel a!&quot;<br />(integer) 0<br />127.0.0.1:7000&gt; PUBLISH channel-b &quot;Hello channel b!&quot;<br />(integer) 0<br />127.0.0.1:7000&gt; <br />127.0.0.1:7000&gt; exit<br />[acool@localhost valkey-cluster-demo]$ # Monitor output in TERMINAL 1 and 2</pre>]]></description>
			<category>- Redis Notes</category>
			<guid isPermaLink="true">https://angelcool.net/sphpblog/blog_index.php?entry=entry240705-213550</guid>
			<author>Angel</author>
			<pubDate>Fri, 05 Jul 2024 21:35:50 GMT</pubDate>
		</item>
		<item>
			<title>Elixir: Making Concurrent API Calls</title>
			<link>https://angelcool.net/sphpblog/blog_index.php?entry=entry240413-024712</link>
			<description><![CDATA[<pre>angelcool@fedora-laptop$<br />angelcool@fedora-laptop$date<br />Fri Apr 12 07:51:16 PM PDT 2024<br />angelcool@fedora-laptop$ls lib/<br />coolprogram.ex  coordinator.ex  worker.ex<br />angelcool@fedora-laptop$cat lib/coolprogram.ex <br />defmodule CoolProgram do<br />  def temperature_of(cities) do<br />    coordinator_pid = spawn(CoolProgram.Coordinator, :loop, [[], Enum.count(cities)])<br />    cities |&gt; Enum.each(fn city -&gt;<br />        worker_pid = spawn(CoolProgram.Worker, :loop, [])<br />        send(worker_pid, {coordinator_pid, city})<br />    end)<br />  end<br />end<br />angelcool@fedora-laptop$cat lib/coordinator.ex <br />defmodule CoolProgram.Coordinator do<br /><br />  def loop(results \\ [], results_expected) do<br />    receive do<br />      {:ok, result} -&gt;<br />        new_results = [result|results]<br />        if results_expected == Enum.count(new_results) do<br />          send(self(), :exit)<br />        end<br />        loop(new_results, results_expected)<br />      :exit -&gt;<br />          IO.puts(results |&gt; Enum.sort |&gt; Enum.join(&quot;, &quot;))<br />        _-&gt;<br />          loop(results, results_expected)<br />    end<br />  end<br /><br />end<br />angelcool@fedora-laptop$cat lib/worker.ex <br />defmodule CoolProgram.Worker do<br /><br />  def temperature_of(location) do<br />    result = url_for(location)<br />      |&gt; HTTPoison.get<br />      |&gt; parse_response<br />    case result do<br />      {:ok, temp} -&gt;<br />        &quot;#{location}: #{temp}° C&quot;<br />      :error -&gt;<br />        &quot;#{location} not found&quot;<br />    end<br />  end<br /><br />  defp url_for(location) do<br />    location = URI.encode(location)<br />    &quot;http://api.openweathermap.org/data/2.5/weather?q=#{location}&amp;appid=#{apikey()}&quot;<br />  end<br /><br />  defp parse_response({:ok, %HTTPoison.Response{body: body, status_code: 200}}) do<br />    body<br />      |&gt; JSON.decode!<br />      |&gt; compute_temperature()<br />  end<br /><br />  defp parse_response(_) do<br />    :error<br />  end<br /><br />  defp compute_temperature(json) do<br />    try do<br />      temp = (json[&quot;main&quot;][&quot;temp&quot;]-273.15)<br />        |&gt; Float.round(1)<br />      {:ok, temp}<br />    rescue<br />      _-&gt; :error<br />    end<br />  end<br /><br />  defp apikey do<br />    &quot;XXXXXXXXXXXXXXXXXXXXXXXXXXXX&quot;<br />  end<br /><br />  def loop do<br />    receive do<br />      {sender_pid, location}-&gt;<br />        send(sender_pid, {:ok, temperature_of(location)})<br />      _-&gt;<br />        IO.puts &quot;don&#039;t know how to process this message&quot;<br />    end<br />    loop()<br />  end<br />end<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$iex --version<br />IEx 1.15.7 (compiled with Erlang/OTP 26)<br />angelcool@fedora-laptop$iex -S mix<br />Compiling 1 file (.ex)<br />Erlang/OTP 26 [erts-14.2.2] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]<br /><br />Interactive Elixir (1.15.7) - press Ctrl+C to exit (type h() ENTER for help)<br />iex(1)&gt; cities=[&quot;San Diego&quot;, &quot;Merida&quot;, &quot;Singapore&quot;, &quot;Los Angeles&quot;, &quot;Mexico City&quot;, &quot;Miami&quot;, &quot;Temecula&quot;, &quot;Buenos Aires&quot;, &quot;Ojai&quot; ]<br />[&quot;San Diego&quot;, &quot;Merida&quot;, &quot;Singapore&quot;, &quot;Los Angeles&quot;, &quot;Mexico City&quot;, &quot;Miami&quot;,<br /> &quot;Temecula&quot;, &quot;Buenos Aires&quot;, &quot;Ojai&quot;]<br />iex(2)&gt; CoolProgram.temperature_of(cities)<br />:ok<br />Buenos Aires: 17.0° C, Los Angeles: 14.7° C, Merida: 25.0° C, Mexico City: 22.8° C, Miami: 22.0° C, Ojai: 14.2° C, San Diego: 15.2° C, Singapore: 30.8° C, Temecula: 13.1° C<br />iex(3)&gt;<br /></pre>]]></description>
			<category>- Elixir Notes</category>
			<guid isPermaLink="true">https://angelcool.net/sphpblog/blog_index.php?entry=entry240413-024712</guid>
			<author>Angel</author>
			<pubDate>Sat, 13 Apr 2024 02:47:12 GMT</pubDate>
		</item>
		<item>
			<title>Elixir: Miscellaneous Notes</title>
			<link>https://angelcool.net/sphpblog/blog_index.php?entry=entry240412-190002</link>
			<description><![CDATA[<pre># Filtering files in a directory by filename<br />angelcool@fedora-laptop$date<br />Fri Apr 12 12:02:42 PM PDT 2024<br />angelcool@fedora-laptop$iex<br />...<br />iex(90)&gt; &quot;/home/angelcool/Downloads&quot; \<br />...(90)&gt; |&gt; Path.join(&quot;**/*.rpm&quot;) \<br />...(90)&gt; |&gt; Path.wildcard \<br />...(90)&gt; |&gt; Enum.filter(fn fname -&gt; String.contains?(Path.basename(fname),&quot;dbeaver&quot;) end)<br />[&quot;/home/angelcool/Downloads/dbeaver-ce-24.0.2-stable.x86_64.rpm&quot;]</pre><br /><br /><pre># Making an HTTP GET request<br />iex(18)&gt; :inets.start()<br />:ok<br />iex(19)&gt; :ssl.start()<br />:ok<br />iex(20)&gt; :httpc.request(:get, {&#039;https://www.angelcool.net&#039;, []}, [ssl: :httpc.ssl_verify_host_options(true)], [])<br />...<br /></pre>]]></description>
			<category>- Elixir Notes</category>
			<guid isPermaLink="true">https://angelcool.net/sphpblog/blog_index.php?entry=entry240412-190002</guid>
			<author>Angel</author>
			<pubDate>Fri, 12 Apr 2024 19:00:02 GMT</pubDate>
		</item>
		<item>
			<title>Elixir: Clustering Elixir Nodes - Updating Shared State.</title>
			<link>https://angelcool.net/sphpblog/blog_index.php?entry=entry240406-184727</link>
			<description><![CDATA[<pre><br />angelcool@fedora-laptop$ # Let&#039;s get the date and versions used<br />angelcool@fedora-laptop$date<br />Sat Apr  6 11:51:08 AM PDT 2024<br />angelcool@fedora-laptop$iex --version<br />IEx 1.15.7 (compiled with Erlang/OTP 26)<br />angelcool@fedora-laptop$mix --version<br />Erlang/OTP 26 [erts-14.2.2] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]<br /><br />Mix 1.15.7 (compiled with Erlang/OTP 26)<br />angelcool@fedora-laptop$mix phx.new --version<br />Phoenix installer v1.7.11<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$ # The gist of this post...<br />angelcool@fedora-laptop$<br />angelcool@fedora-laptop$ # Terminal 1<br />angelcool@fedora-laptop$ iex --name a@127.0.0.1<br />iex(a@127.0.0.1)1&gt;<br /><br />angelcool@fedora-laptop$ #Terminal 2<br />angelcool@fedora-laptop$ iex --name b@127.0.0.1<br />Erlang/OTP 26 [erts-14.2.2] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]<br /><br />Interactive Elixir (1.15.7) - press Ctrl+C to exit (type h() ENTER for help)<br />iex(b@127.0.0.1)1&gt; Node.connect :&quot;a@127.0.0.1&quot;<br />true<br />iex(b@127.0.0.1)2&gt; Node.list<br />[:&quot;a@127.0.0.1&quot;]<br />iex(b@127.0.0.1)3&gt;<br /><br /># Terminal 1<br />iex(a@127.0.0.1)&gt; Agent.start(<br />  fn -&gt; %{hello: &quot;world&quot;} end, <br />  name: {:global, GlobalAgent}<br />)<br />{:ok, #PID&lt;0.116.0&gt;} <br /><br /># Terminal 2<br />iex(b@127.0.0.1)4&gt; Agent.get {:global,GlobalAgent}, &amp;(&amp;1)<br />%{hello: &quot;world&quot;}<br /><br /># Terminal 2 - Update state<br />iex(b@127.0.0.1)5&gt; Agent.update {:global, GlobalAgent}, fn _ -&gt; %{hello: &quot;everyone!&quot;}  end<br />:ok<br />iex(b@127.0.0.1)6&gt;<br /><br /># Terminal 2 - Get new state<br />iex(b@127.0.0.1)6&gt; Agent.get {:global,GlobalAgent}, &amp;(&amp;1)<br />%{hello: &quot;everyone!&quot;}<br /><br /># Terminal 1 - Get new state<br />iex(a@127.0.0.1)2&gt; Agent.get {:global,GlobalAgent}, &amp;(&amp;1)<br />%{hello: &quot;everyone!&quot;}</pre>]]></description>
			<category>- Elixir Notes</category>
			<guid isPermaLink="true">https://angelcool.net/sphpblog/blog_index.php?entry=entry240406-184727</guid>
			<author>Angel</author>
			<pubDate>Sat, 06 Apr 2024 18:47:27 GMT</pubDate>
		</item>
	</channel>
</rss>
