<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Remboldt Tech Blog]]></title><description><![CDATA[Remboldt Tech Blog]]></description><link>https://blog.remboldt.eu</link><generator>RSS for Node</generator><lastBuildDate>Wed, 16 Sep 2026 06:21:16 GMT</lastBuildDate><atom:link href="https://blog.remboldt.eu/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How I made a lightweight JavaScript Framework and then used it to build my Website - jasna.js]]></title><description><![CDATA[I am not often using JavaScript, and I am sure that there is already a framework which does the same thing. I didn't even expect to use it, but surprisingly it really helped to build my website.The minified version only takes up 479 bytes. Not even h...]]></description><link>https://blog.remboldt.eu/jasnajs</link><guid isPermaLink="true">https://blog.remboldt.eu/jasnajs</guid><category><![CDATA[js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[framework]]></category><category><![CDATA[documentation]]></category><category><![CDATA[development]]></category><dc:creator><![CDATA[One Remboldt]]></dc:creator><pubDate>Tue, 30 May 2023 20:31:11 GMT</pubDate><content:encoded><![CDATA[<p>I am not often using JavaScript, and I am sure that there is already a framework which does the same thing. I didn't even expect to use it, but surprisingly it really helped to build my website.<br />The minified version only takes up 479 bytes. Not even half a kilobyte!</p>
<p>Get it on <a target="_blank" href="https://github.com/remboldt/JasnaJS">GitHub</a></p>
<h1 id="heading-why-i-built-it">Why I built it</h1>
<h2 id="heading-the-problem-i-tried-to-solve">The problem I tried to solve</h2>
<p>When building a website the HTML file can get heavily nested quite fast. I wanted to split up the website into multiple HTML files, so I can work on each component separately without the file getting too confusing to look at. Then I would simply put every component together in one clearly structured HTML file.</p>
<p>But as I didn't want to learn a complex JS framework with tons of features that would slow down my website, I decided to make my own lightweight and robust framework.</p>
<h2 id="heading-name">Name</h2>
<p>The original name of the script was really simple and overused <code>component_loader.js</code>. So I came up with this idea: As this framework makes your code clearer and more readable, I chose <code>jasna.js</code> for publishing it. Ясно ("Yasno") is the Russian word for "understand" or "clear" and it is pronounced like "Jansa".</p>
<h1 id="heading-development">Development</h1>
<h2 id="heading-selector">Selector</h2>
<p>First of all, I had to figure out how to clarify which parts of the HTML document should be affected at all. First I had the idea to go through each <code>&lt;div&gt;</code> tag and check if it has the value <code>"component"</code> in the class attribute. But then I had a much better idea. I could just create a unique tag: <code>&lt;component&gt;</code>. This one is very easy to remember and you can find it more quickly in the code, so I decided on this. Also, this was very simple to implement:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> components = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"component"</span>);
</code></pre>
<p>Now I had a collection of every element with this specific tag name.</p>
<h2 id="heading-looping-through">Looping through</h2>
<p>Now I had a collection of items. But I could only work with one at a time. So I made a simple for-loop to accomplish this.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> components = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"component"</span>);
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; components.length; i++) {
    <span class="hljs-comment">// do stuff with each components[i]</span>
}
</code></pre>
<h2 id="heading-source">Source</h2>
<p>Next, I had to come up with an Idea, how the developer specifies, where the component is stored at. In the first version of the script, I checked the id attribute for the URL of the source.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> url = component.id; <span class="hljs-comment">//was a bad Idea</span>
</code></pre>
<p>But later I figured, that it would be much smarter to check the src attribute. Like in <code>&lt;img src=""&gt;</code> or <code>&lt;script src=""&gt;</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> components = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"component"</span>);
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; components.length; i++) {
    <span class="hljs-keyword">var</span> url = components[i].attributes[<span class="hljs-string">'src'</span>].textContent; <span class="hljs-comment">//beter idea</span>
}
</code></pre>
<h2 id="heading-fletching-my-teeth-on-fetching-data">Fletching my teeth on fetching data</h2>
<p>Now, for this part, I was overwhelmed, as I have barely used asynchronous functions before. I have used "threading" in Python before, which is roughly the equivalent of JavaScript's async functions.</p>
<p>At the end of watching several YouTube Videos, reading some documentations at MDN, and some tutorials. I have decided to go with XMLHttpRequest.<br />On <a target="_blank" href="https://www.w3schools.com/XML/ajax_xmlhttprequest_response.asp">W3Schools</a> I found exactly what I was looking for:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> components = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"component"</span>);
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; components.length; i++) {
    <span class="hljs-keyword">var</span> url = components[i].attributes[<span class="hljs-string">'src'</span>].textContent; 

    <span class="hljs-keyword">var</span> xhttp = <span class="hljs-keyword">new</span> XMLHttpRequest();
    xhttp.onreadystatechange = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.readyState == <span class="hljs-number">4</span> &amp;&amp; <span class="hljs-built_in">this</span>.status == <span class="hljs-number">200</span>) {
           content = xhttp.responseText;
           components[i].innerHTML = content;
        }
    };
    xhttp.open(<span class="hljs-string">"GET"</span>, url, <span class="hljs-literal">true</span>);
    xhttp.send();

}
</code></pre>
<p>At this point, the code was already working (I think). But I have decided to split the code up a bit because I wanted to implement live data. I made a separate function called <code>load_component()</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">load_content</span>(<span class="hljs-params">component</span>) </span>{
    <span class="hljs-keyword">var</span> url = component.attributes[<span class="hljs-string">'src'</span>].textContent;

    <span class="hljs-keyword">var</span> xhttp = <span class="hljs-keyword">new</span> XMLHttpRequest();
    xhttp.onreadystatechange = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.readyState == <span class="hljs-number">4</span> &amp;&amp; <span class="hljs-built_in">this</span>.status == <span class="hljs-number">200</span>) {
           content = xhttp.responseText;
           component.innerHTML = content;
        }
    };
    xhttp.open(<span class="hljs-string">"GET"</span>, url, <span class="hljs-literal">true</span>);
    xhttp.send();
}

<span class="hljs-keyword">var</span> components = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"component"</span>);
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; components.length; i++) {
    load_content(components[i]);
}
</code></pre>
<p>You can see this in action on my webpage (website updated by now)</p>
<h2 id="heading-extra-feature-livecomponents">Extra feature: "live_components"</h2>
<p>At this point, you could only load everything just once. But I have decided, that dynamic content would be cooler. I won't go into details here, because the article is already really long.</p>
<h3 id="heading-extending-the-for-loop">Extending the for-Loop</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; components.length; i++) {
    load_content(components[i]);

    <span class="hljs-comment">// If the first value of the class attribute is "refresh", then the component will be passed to a async function, which contains a never ending while-Loop</span>
    <span class="hljs-keyword">if</span> (components[i].classList[<span class="hljs-number">0</span>] == <span class="hljs-string">"refresh"</span>) {
        live_components(components[i])
    }
}
</code></pre>
<p>Example:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">component</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://examp.le/dynamic.php"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"refresh"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">component</span>&gt;</span>
</code></pre>
<h3 id="heading-the-asynchronous-function">The asynchronous function</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">live_components</span>(<span class="hljs-params">component</span>) </span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(component.classList[<span class="hljs-number">1</span>])){
        <span class="hljs-comment">// If the second value of the class attribute is not a number (NaN), the function will check every 2 seconds (2000ms) if the content is new</span>
        sleep_time = <span class="hljs-number">2000</span>;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// If the second value is a number, then this will be taken as the "sleep_time"</span>
        sleep_time = <span class="hljs-built_in">parseInt</span>(component.classList[<span class="hljs-number">1</span>]);
    }

    <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
        <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(r, sleep_time));
        load_content(component);
    }
}
</code></pre>
<p>Now you can specify in what time intervals it should check for updated content:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">component</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"dynamic.php"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"refresh 10000"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">component</span>&gt;</span>
<span class="hljs-comment">&lt;!-- it will re-check every 10 seconds --&gt;</span>
</code></pre>
<h3 id="heading-only-reload-the-content-if-it-has-changed">Only reload the content if it has changed</h3>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">load_content</span>(<span class="hljs-params">component</span>) </span>{
    <span class="hljs-keyword">var</span> url = component.attributes[<span class="hljs-string">'src'</span>].textContent;

    <span class="hljs-keyword">var</span> xhttp = <span class="hljs-keyword">new</span> XMLHttpRequest();
    xhttp.onreadystatechange = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.readyState == <span class="hljs-number">4</span> &amp;&amp; <span class="hljs-built_in">this</span>.status == <span class="hljs-number">200</span>) {
            content = xhttp.responseText;

            <span class="hljs-comment">// I have added this if-condition, to check if the content of the component is already the same as the newly fetched content</span>
            <span class="hljs-keyword">if</span> (content !== component.innerHTML) {
                <span class="hljs-comment">// Only updates if the source content has changed</span>
                component.innerHTML = content;
            }
        }
    };
    xhttp.open(<span class="hljs-string">"GET"</span>, url, <span class="hljs-literal">true</span>);
    xhttp.send();
}
</code></pre>
<h1 id="heading-finished-code">Finished Code</h1>
<p>jasna.js</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">load_content</span>(<span class="hljs-params">component</span>) </span>{
    <span class="hljs-keyword">var</span> url = component.id;

    <span class="hljs-keyword">var</span> xhttp = <span class="hljs-keyword">new</span> XMLHttpRequest();
    xhttp.onreadystatechange = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.readyState == <span class="hljs-number">4</span> &amp;&amp; <span class="hljs-built_in">this</span>.status == <span class="hljs-number">200</span>) {
           content = xhttp.responseText;
           component.innerHTML = content;
        }
    };
    xhttp.open(<span class="hljs-string">"GET"</span>, url, <span class="hljs-literal">true</span>);
    xhttp.send();
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">live_components</span>(<span class="hljs-params">component</span>) </span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(component.classList[<span class="hljs-number">1</span>])){
        sleep_time = <span class="hljs-number">2000</span>;
    } <span class="hljs-keyword">else</span> {
        sleep_time = <span class="hljs-built_in">parseInt</span>(component.classList[<span class="hljs-number">1</span>]);
    }
    <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
        <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(r, sleep_time));
        load_content(component);
    }
}

<span class="hljs-keyword">var</span> components = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"component"</span>);

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; components.length; i++) {
    load_content(components[i]);
    <span class="hljs-keyword">if</span> (components[i].classList[<span class="hljs-number">0</span>] == <span class="hljs-string">"refresh"</span>) {
        live_components(components[i])
    }
}
</code></pre>
<h1 id="heading-live-example">Live Example</h1>
<p>As I said, I have written my website with the help of this little framework. And the index file looks really clear and readable.</p>
<p>(Website updated by now)</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>One Remboldt<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"css/bulma.min.css"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"css/style.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">component</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"components/navbar.html"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">component</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">component</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"components/header.html"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">component</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">component</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"components/about_me.html"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">component</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">component</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"components/links.html"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">component</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">component</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"components/bottom_part.html"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">component</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">component</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"components/footer.html"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">component</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"js/component_loader.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"js/counter.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>View <a target="_blank" href="https://github.com/remboldt/JasnaJS">JasnaJS on GitHub</a>.</p>
]]></content:encoded></item><item><title><![CDATA[adf.ly acquired by Linkvertise - Recreating missing feature]]></title><description><![CDATA[The link shortener adf.ly is shutting down soon, all accounts will have to migrate to Linkvertise. Sadly, Linkvertise lacks one feature I loved on adf.ly:Creating single URLs without having to interact with a graphical user interface. They only provi...]]></description><link>https://blog.remboldt.eu/recreating-missing-adfly-feature-for-linkvertise</link><guid isPermaLink="true">https://blog.remboldt.eu/recreating-missing-adfly-feature-for-linkvertise</guid><category><![CDATA[Monetization]]></category><category><![CDATA[Url Shortener]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[adfly]]></category><category><![CDATA[linkvertise]]></category><dc:creator><![CDATA[One Remboldt]]></dc:creator><pubDate>Thu, 30 Mar 2023 01:00:39 GMT</pubDate><content:encoded><![CDATA[<p>The link shortener <a target="_blank" href="https://adf.ly/"><em>adf.ly</em></a> is shutting down soon, all accounts will have to migrate to <a target="_blank" href="https://publisher.linkvertise.com/"><em>Linkvertise</em></a>. Sadly, <em>Linkvertise</em> lacks one feature I loved on <em>adf.ly</em>:<br />Creating single URLs without having to interact with a graphical user interface. They only provide a "full-page script", which replaces all links on the site with Linkvertise Ads. This was an absolute overkill for my use case. So I created my own little script, after analyzing how their full-page script works.</p>
<h1 id="heading-step-1-analyzing-javascript">Step 1 - Analyzing JavaScript</h1>
<h2 id="heading-11-unminifying-the-full-page-script">1.1 - Unminifying the Full-Page Script</h2>
<p>The full-page script is hosted on <a target="_blank" href="https://publisher.linkvertise.com/cdn/linkvertise.js">https://publisher.linkvertise.com/cdn/linkvertise.js</a>. But they recently minified their script, after I criticized their method of generating links with junk data in them to make them look more complex.</p>
<p>So, when I started working on my script, I had to first unminify the code with <a target="_blank" href="https://unminify.com/">https://unminify.com/</a>.</p>
<h2 id="heading-12-understanding-how-their-links-work">1.2 - Understanding, how their links work</h2>
<p>From lines 34 to 38, I found this:</p>
<pre><code class="lang-javascript"> debug(<span class="hljs-string">"Converting '"</span> + base_href + <span class="hljs-string">"'"</span>);
 <span class="hljs-keyword">var</span> base_url = <span class="hljs-string">"https://link-to.net/"</span> + user_id + <span class="hljs-string">"/"</span> + <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">1000</span> + <span class="hljs-string">"/dynamic/"</span>;
 <span class="hljs-keyword">var</span> href = base_url + <span class="hljs-string">"?r="</span> + btoa(<span class="hljs-built_in">encodeURI</span>(base_href));
 link.href = href;
 link.setAttribute(<span class="hljs-string">"_target"</span>, <span class="hljs-string">"blank"</span>);
</code></pre>
<p>The base URL is <em>https://link-to.net/</em>, after that we have the user id, then a random number to make it look more confusing, then <em>/dynamic/?r=,</em> and finally we encode the URL into an ASCII Format with <em>encodeURI(url)</em>. The URI is then encoded in base64 with the btoa() function. In the end, we get this URL-Format:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"https://link-to.net/${user_id}/${random_number}/dynamic/?r=${base64}"</span>
</code></pre>
<h1 id="heading-step-2-writing-own-script">Step 2 - Writing own Script</h1>
<h2 id="heading-21-link-transformer">2.1 - Link transformer</h2>
<p>The first step was really simple. I took the URL format, we saw in Part 1, and have put it into a separate function, so developers can use it in their JavaScript code.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">linkvertise_url</span>(<span class="hljs-params">user_id, base_href</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"https://link-to.net/"</span> + user_id + <span class="hljs-string">"/"</span> + <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">1000</span> + <span class="hljs-string">"/dynamic/?r="</span> + btoa(<span class="hljs-built_in">encodeURI</span>(base_href));
}
</code></pre>
<h2 id="heading-22-replacing-links-in-html-dom">2.2 - Replacing links in HTML DOM</h2>
<p>First I had to find an easy way, someone could select individual links in their HTML code, and "linkvertise" them.</p>
<p>My solution was to first select every &lt;a&gt; tag and store it in a variable:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> elements = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"a"</span>);
</code></pre>
<p>Now I will loop through every &lt;a&gt; tag with this for-loop:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; elements.length; i++) {
    <span class="hljs-comment">// Code goes here</span>
}
</code></pre>
<p>In this for-loop, I will check for every element, if the class attribute contains "linkvertise":</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; elements.length; i++) {
    <span class="hljs-keyword">if</span> (elements[i].classList[<span class="hljs-number">0</span>] == <span class="hljs-string">"linkvertise"</span>) {
        <span class="hljs-comment">// Rest here</span>
    }
}
</code></pre>
<p>Lastly, I will read out the <em>href</em> attribute's content and pass it to <em>linkvertise_url();</em> to replace the current <em>href</em> with the newly generated Linkvertise link:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; elements.length; i++) {
    <span class="hljs-keyword">if</span> (elements[i].classList[<span class="hljs-number">0</span>] == <span class="hljs-string">"linkvertise"</span>) {
        <span class="hljs-comment">// Reading out current href</span>
        <span class="hljs-keyword">let</span> base_href = elements[i].attributes[<span class="hljs-string">'href'</span>].textContent;

        <span class="hljs-comment">// Generating Linkvertise URL</span>
        <span class="hljs-keyword">let</span> url = linkvertise_url(user_id, base_href);

        <span class="hljs-comment">// Set new href attribute</span>
        elements[i].setAttribute(<span class="hljs-string">"href"</span>, url);

        <span class="hljs-comment">// Always in new tab</span>
        elements[i].setAttribute(<span class="hljs-string">"target"</span>, <span class="hljs-string">"_blank"</span>);
    }
}
</code></pre>
<p>I will have to put the for-loop into a function (<em>linkvertise</em>) and only call it, once the &lt;body&gt; has loaded. The easiest way, if the developer simply includes <em>onload="linkvertise()"</em>.</p>
<h1 id="heading-full-code">Full Code</h1>
<p>You can either host the script for yourself or include it in your &lt;script&gt; tag. But I recommend you just use my CDN, which would be the easiest and cleanest way in my oppinion.</p>
<h2 id="heading-javascript">JavaScript</h2>
<p>Copy + Paste</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">linkvertise_url</span>(<span class="hljs-params">user_id, base_href</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"https://link-to.net/"</span> + user_id + <span class="hljs-string">"/"</span> + <span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">1000</span> + <span class="hljs-string">"/dynamic/?r="</span> + btoa(<span class="hljs-built_in">encodeURI</span>(base_href));
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">linkvertise</span>(<span class="hljs-params">user_id</span>) </span>{
    <span class="hljs-comment">// Get every &lt;a&gt; tag</span>
    <span class="hljs-keyword">let</span> elements = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"a"</span>);

    <span class="hljs-comment">// Loop through every &lt;a&gt; tag</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; elements.length; i++) {
        <span class="hljs-comment">// If class of &lt;a&gt; tag contains "linkverse"</span>
        <span class="hljs-keyword">if</span> (elements[i].classList[<span class="hljs-number">0</span>] == <span class="hljs-string">"linkvertise"</span>) {
            <span class="hljs-comment">// Extract the url from href attribute</span>
            <span class="hljs-keyword">let</span> base_href = elements[i].attributes[<span class="hljs-string">'href'</span>].textContent;

            <span class="hljs-comment">// Pass the user_id and url to linkvertise_url();</span>
            url = linkvertise_url(user_id, base_href);

            <span class="hljs-comment">// Replace current url with new one, and link in new tab</span>
            elements[i].setAttribute(<span class="hljs-string">"href"</span>, url);
            elements[i].setAttribute(<span class="hljs-string">"target"</span>, <span class="hljs-string">"_blank"</span>);
        }
    }
}
</code></pre>
<p>CDN</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.remboldt.eu/linkvertise_single_url.js"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<h2 id="heading-example-usage-in-html">Example Usage in HTML</h2>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>linkvertise single url example<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">onload</span>=<span class="hljs-string">"linkvertise('644202');"</span>&gt;</span>
<span class="hljs-comment">&lt;!-- Replace 644202 with your user id --&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://blog.remboldt.eu/"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"linkvertise"</span>&gt;</span>My Blog<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- add class="linkvertise" to a-tag --&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.remboldt.eu/linkvertise_single_url.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- include script at the bottom --&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
        <span class="hljs-keyword">let</span> url = linkvertise_url(<span class="hljs-string">'644202'</span>, <span class="hljs-string">'https://blog.remboldt.eu/'</span>);
        <span class="hljs-comment">// Use this function to convert URLs in JavaScript</span>

        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Generatrd in JavaScript: "</span> + url);
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h3 id="heading-live-demohttpscdnremboldteulinkvertisesingleurl"><a target="_blank" href="https://cdn.remboldt.eu/linkvertise_single_url">Live Demo</a></h3>
<p>Thanks for reading :)</p>
]]></content:encoded></item><item><title><![CDATA[Making a Python wrapper for IPFS]]></title><description><![CDATA[I've wanted to publish my first article about an encrypted, decentralized chat app running on IPFS. I had already built a private IPFS library, but I wanted to use a public one for the article. I tried out two different public libraries. One of them ...]]></description><link>https://blog.remboldt.eu/ipfslib</link><guid isPermaLink="true">https://blog.remboldt.eu/ipfslib</guid><category><![CDATA[ipfs]]></category><category><![CDATA[Python]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[library]]></category><dc:creator><![CDATA[One Remboldt]]></dc:creator><pubDate>Mon, 09 Jan 2023 03:00:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1671624091069/nRTE4zM5Y.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've wanted to publish my first article about an encrypted, decentralized chat app running on IPFS. I had already built a private IPFS library, but I wanted to use a public one for the article. I tried out two different public libraries. One of them simply didn't work and the other one was deprecated.<br />So here I am rebuilding my library publically!</p>
<h1 id="heading-step-1-preparing">Step 1 - Preparing</h1>
<h2 id="heading-reading-the-documentation">Reading the documentation</h2>
<p>The last time I've build this, it wasn't in the most elegant way. I used the CLI Tools and extracted the data I needed with regex. I have done many unconventional things, but I was too lazy to read the documentation and wanted to get a mini-project done quickly to show my friends. As I am building this publically now, I will read the IPFS documentation (<a target="_blank" href="https://docs.ipfs.tech/reference/kubo/rpc/">IPFS Kubo RPC API</a>).</p>
<h2 id="heading-what-do-i-want-to-achieve-with-this-library">What do I want to achieve with this library?</h2>
<p>As far as Version 1 goes, I only want to implement basic functionality, so I can finish my first intended article. In particular, I want to be able to do at least the following things:</p>
<ul>
<li><p>Add files to IPFS</p>
</li>
<li><p>Get files from IPFS</p>
</li>
<li><p>Remove files from IPFS</p>
</li>
<li><p>Generate IPNS Keys</p>
</li>
<li><p>List IPNS Keys</p>
</li>
<li><p>Update IPNS values</p>
</li>
</ul>
<h2 id="heading-creating-the-folder-structure">Creating the folder structure</h2>
<p>At this point, I have to create the root folder. This will be the name of my library. I will call it <strong>ipfslib</strong>, so it's easier to confuse with ipfsapi. Every module has it's own file, this way it is less cluttered and easier to update afterwards.</p>
<pre><code class="lang-plaintext">    ipfslib
    │   connect.py
    │   __init__.py
    │
    ├───IPFS
    │   │   add.py
    │   │   cat.py
    │   │   get.py
    │   │   rem.py
    │   │   resolve.py
    │   │   __init__.py
    │
    └───Key
        │   generate.py
        │   list.py
        │   publish.py
        │   rename.py
        │   __init__.py
</code></pre>
<p>I included everything I want to have in my first version. This is all I need for my next project.</p>
<h2 id="heading-creating-the-connector">Creating the Connector</h2>
<p>I want the user to be able to specify where the API-endpoint is, instead of assuming standard values. Basically this is all, what <em>connect.py</em> does, it stores the IP-address and the port of the API-endpoint:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Connect</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, ip_address, port</span>):</span>
        self.endpoint = str(ip_address) + <span class="hljs-string">":"</span> + str(port)
</code></pre>
<p>But I included some checks to check if the API is responding and I included standard parameters, so users could simply write <code>ipfslib.Connect()</code>, instead of typing <code>ipfslib.Connect('127.0.0.1', 5001)</code>.</p>
<pre><code class="lang-python"><span class="hljs-comment"># ipfslib/connect.py</span>
<span class="hljs-keyword">import</span> requests

<span class="hljs-comment"># Sets up the API-Connector</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Connect</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, ip_address=<span class="hljs-string">"localhost"</span>, port=<span class="hljs-number">5001</span></span>):</span>

        <span class="hljs-comment"># Check if port has the right format</span>
        <span class="hljs-keyword">if</span> str(port).isnumeric() == <span class="hljs-literal">False</span>:
            <span class="hljs-keyword">raise</span> TypeError(<span class="hljs-string">"The given port is not numeric"</span>)
        <span class="hljs-keyword">elif</span> int(port) &lt;= <span class="hljs-number">0</span> <span class="hljs-keyword">or</span> int(port) &gt;= <span class="hljs-number">65536</span>:
            <span class="hljs-keyword">raise</span> ValueError(<span class="hljs-string">"Port number has to be between 1 and 65535"</span>)

        <span class="hljs-comment"># Saves API Endpoint if port checks are passed</span>
        self.endpoint = str(ip_address) + <span class="hljs-string">":"</span> + str(port)

        <span class="hljs-comment"># Checks if the API is responding</span>
        response = requests.post(<span class="hljs-string">'http://{endpoint}/api/v0/bitswap/stat'</span>.format(endpoint=self.endpoint))
        <span class="hljs-keyword">if</span> response.status_code != <span class="hljs-number">200</span>:
            <span class="hljs-keyword">raise</span> Exception(<span class="hljs-string">"The given endpoint isn't working as intended"</span>)
</code></pre>
<h1 id="heading-step-2-wrapping-those-apis-up">Step 2 - Wrapping those APIs up😋</h1>
<p>You don't need to be a professional programmer to do this stuff - even I can do it.</p>
<p>Let's say, I want to add a file to IPFS. The way to do it is quite simple, because the IPFS documentation has CURL examples. Here is a quick overview of what I did it:</p>
<ol>
<li><p><a target="_blank" href="http://docs.ipfs.tech/reference/kubo/rpc/#api-v0-add">Go to the documentation, where adding files is specified</a></p>
</li>
<li><p>Copy the provided CURL example</p>
</li>
<li><p><a target="_blank" href="https://curlconverter.com/python/">Paste it at curlconverter.com</a></p>
</li>
<li><p>Integrate the Python Code into the function</p>
</li>
<li><p>Read out the JSON response and extract relevant values</p>
</li>
</ol>
<h2 id="heading-example-generating-ipns-key">Example: Generating IPNS key</h2>
<p>The CURL example in the IPFS documentation:</p>
<pre><code class="lang-plaintext">curl -X POST "http://127.0.0.1:5001/api/v0/key/gen?arg=&lt;name&gt;&amp;type=ed25519&amp;size=&lt;value&gt;&amp;ipns-base=base36"
</code></pre>
<p>Removing unnecessary things and formatting:</p>
<pre><code class="lang-plaintext">curl -X POST "http://{endpoint}/api/v0/key/gen?arg="
</code></pre>
<p>Using curlconverter.com:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests

params = {
    <span class="hljs-string">'arg'</span>: <span class="hljs-string">''</span>,
}

response = requests.post(<span class="hljs-string">'http://{endpoint}/api/v0/key/gen'</span>, params=params)
</code></pre>
<p>Implementing it into a function, which takes the JSON response and extracts the ipns_name of the newly created key:</p>
<pre><code class="lang-python"><span class="hljs-comment"># ipfslib/Key/generate.py</span>
<span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> requests

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate</span>(<span class="hljs-params">api, key_name</span>):</span>
    params = {
        <span class="hljs-string">'arg'</span>: key_name,
    }
    response = requests.post(<span class="hljs-string">'http://{endpoint}/api/v0/key/gen'</span>.format(api.endpoint), params=params)
    ipns_name = json.loads(response.text)[<span class="hljs-string">"Id"</span>]
    <span class="hljs-keyword">return</span> ipns_name
</code></pre>
<p>I did this for every feature I wanted to have in my library. Some were more complex than others, I showed you the most simple function there was for this example.<br />Other modules had more complex JSON responses or more functionality.</p>
<h2 id="heading-including-everything-in-initpy">Including everything in __init__.py</h2>
<p>I don't want the user to import every module separately, so I'll include them in those nice little __init__.py files.</p>
<pre><code class="lang-python"><span class="hljs-comment"># ipfslib/__init__.py</span>
<span class="hljs-keyword">from</span> ipfslib.connect <span class="hljs-keyword">import</span> Connect
<span class="hljs-keyword">from</span> ipfslib <span class="hljs-keyword">import</span> Key
<span class="hljs-keyword">from</span> ipfslib <span class="hljs-keyword">import</span> IPFS
</code></pre>
<pre><code class="lang-python"><span class="hljs-comment"># ipfslib/IPFS/__init__.py</span>
<span class="hljs-keyword">from</span> ipfslib.IPFS.add <span class="hljs-keyword">import</span> add
<span class="hljs-keyword">from</span> ipfslib.IPFS.cat <span class="hljs-keyword">import</span> cat
<span class="hljs-keyword">from</span> ipfslib.IPFS.get <span class="hljs-keyword">import</span> get
<span class="hljs-keyword">from</span> ipfslib.IPFS.rem <span class="hljs-keyword">import</span> rem
<span class="hljs-keyword">from</span> ipfslib.IPFS.resolve <span class="hljs-keyword">import</span> resolve
</code></pre>
<pre><code class="lang-python"><span class="hljs-comment"># ipfslib/Key/__init__.py</span>
<span class="hljs-keyword">from</span> ipfslib.Key.generate <span class="hljs-keyword">import</span> generate
<span class="hljs-keyword">from</span> ipfslib.Key.list <span class="hljs-keyword">import</span> list
<span class="hljs-keyword">from</span> ipfslib.Key.publish <span class="hljs-keyword">import</span> publish
<span class="hljs-keyword">from</span> ipfslib.Key.rename <span class="hljs-keyword">import</span> rename
</code></pre>
<h1 id="heading-step-3-publishing">Step 3 - Publishing</h1>
<p>Surprisingly this was taking longer than actually programming because it is my first time actually doing this last step of publishing my project. In future projects, this won't take that long anymore, because I've learned everything important now.<br />Like how to structure a <code>setup.py</code> file or how to use twine, which is fairly easy.</p>
<h2 id="heading-writing-documentation">Writing documentation</h2>
<p>I explained how to use each module quickly in the README.md file. There is nothing too much to explain here. I had to look at how Markup works, but it was a simple process as a whole.</p>
<h2 id="heading-creating-the-setup-file">Creating the setup file</h2>
<p>The setup.py file ended up looking like this. I had to change the version from 0.1 to 0.1.0, because I messed up the markup file on my first try uploading. I took inspiration from <a target="_blank" href="https://github.com/NeuralNine/vidstream/blob/main/setup.py">here</a> to fix the problem with my project description.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> setuptools <span class="hljs-keyword">import</span> setup, find_packages
<span class="hljs-keyword">import</span> codecs
<span class="hljs-keyword">import</span> os

here = os.path.abspath(os.path.dirname(__file__))

<span class="hljs-keyword">with</span> codecs.open(os.path.join(here, <span class="hljs-string">"README.md"</span>), encoding=<span class="hljs-string">"utf-8"</span>) <span class="hljs-keyword">as</span> fh:
    long_description = <span class="hljs-string">"\n"</span> + fh.read()

setup(
    name=           <span class="hljs-string">"ipfslib"</span>,
    version=        <span class="hljs-string">"0.1.0"</span>,
    author=         <span class="hljs-string">"Christian Remboldt"</span>,
    author_email=   <span class="hljs-string">"remboldt@proton.me"</span>,
    description=    <span class="hljs-string">"IPFS Library for Python"</span>,
    long_description_content_type=<span class="hljs-string">"text/markdown"</span>,
    long_description=long_description,
    packages=find_packages(),
    install_requires=[],
    keywords=[<span class="hljs-string">'python'</span>, <span class="hljs-string">'ipfs'</span>, <span class="hljs-string">'api'</span>, <span class="hljs-string">'decentral'</span>, <span class="hljs-string">'networking'</span>, <span class="hljs-string">'ipns'</span>],
    classifiers=[
        <span class="hljs-string">"Programming Language :: Python :: 3"</span>
    ]
)
</code></pre>
<h2 id="heading-uploading">Uploading</h2>
<p>First I had to build the <code>setup.py</code> file</p>
<pre><code class="lang-python">py setup.py sdist
</code></pre>
<p>After python had created the <em>dist</em> folder, I could upload its contents to PyPi with twine.</p>
<pre><code class="lang-python">py -m pip install twine
py -m twine upload dist/*
</code></pre>
<p>AND DONE!</p>
<h1 id="heading-note">Note</h1>
<p>I uploaded some usage examples on GitHub:<br /><a target="_blank" href="https://github.com/remboldt/ipfslib/tree/main/examples">https://github.com/remboldt/ipfslib/tree/main/examples</a><a target="_blank" href="https://pypi.org/project/ipfslib/">  
</a>Have a nice day!</p>
<p>PyPi Project Page: <a target="_blank" href="https://pypi.org/project/ipfslib/">https://pypi.org/project/ipfslib/</a><br />GitHub Repository: <a target="_blank" href="https://github.com/remboldt/ipfslib">https://github.com/remboldt/ipfslib</a>/</p>
]]></content:encoded></item></channel></rss>