Mastering Chrome Extensions: A Guide to Reading and Writing Data

Understanding the Fundamentals of Chrome Extensions

The Manifest File

Within the ever-evolving digital panorama, internet searching has turn out to be an indispensable a part of our day by day lives. Whereas the web gives a wealth of data, the expertise can typically really feel clunky, repetitive, or just not tailor-made to particular person wants. That is the place the facility of Chrome Extensions comes into play. These small however mighty packages, crafted for the Google Chrome browser, provide a exceptional capacity to personalize, improve, and automate numerous points of internet searching. This text serves as a complete information to understanding the way to leverage the facility of Chrome Extensions, particularly specializing in the essential expertise of studying and writing knowledge. By mastering these fundamentals, you’ll be able to unlock an entire new dimension of potentialities, remodeling your searching expertise from passive consumption to lively manipulation and customization.

Background Scripts

Earlier than diving into the specifics of studying and writing knowledge, it is vital to determine a strong understanding of the underlying structure of a Chrome Extension. This foundational data will empower you to construct sturdy and environment friendly extensions. The cornerstone of each Chrome Extension lies in its **manifest file**.

Content material Scripts

The manifest file, sometimes named `manifest.json`, is a vital JSON-formatted file. It serves because the blueprint, offering important details about the extension to the browser. Consider it because the extension’s identification card, defining its goal, performance, and permissions. Key parts throughout the `manifest.json` embrace: `manifest_version` which denotes the model of the manifest file specification getting used, `identify` which is the human-readable identify of the extension, `model` to trace extension releases, `description` to offer a quick overview, and, crucially, the `permissions` part. The `permissions` part lists the entry privileges the extension requires, reminiscent of accessing internet web page content material, studying cookies, or interacting with community requests. With out the right permissions, your extension merely will not be capable of carry out its meant duties. A simplified instance of a `manifest.json` might seem like this:


{
  "manifest_version": 3,
  "identify": "My Customized Extension",
  "model": "1.0",
  "description": "An extension that modifies internet content material.",
  "permissions": [
    "activeTab",
    "storage"
  ],
  "motion": {
    "default_popup": "popup.html"
  },
  "background": {
    "service_worker": "background.js"
  }
}

Popup Pages

Subsequent, we encounter **background scripts**. These scripts function within the background, persistently working within the browser even when no particular internet web page is actively open or when the consumer is just not instantly interacting along with your extension. They function the “brains” of your extension, dealing with background duties, monitoring occasions, and managing general extension logic. Background scripts can carry out a wide range of operations, from monitoring consumer exercise to intercepting community requests. They’re declared within the `manifest.json` file and outlined in a devoted script file, sometimes named `background.js`.

Then there are **content material scripts**. Content material scripts are the facility instruments that inject your code into internet pages. When a content material script is specified, it executes instantly throughout the context of a webpage, getting access to the Doc Object Mannequin (DOM) of that web page. This enables content material scripts to work together with internet content material, modifying it, extracting knowledge, and even including new components. The pages on which the content material script runs are specified within the `manifest.json` file, utilizing the `matches` property. This property makes use of a sample matching system that ensures content material scripts solely execute on licensed web sites. Content material scripts present the first means for interacting with internet web page knowledge.

Lastly, **popup pages** are important for offering a consumer interface (UI) on your extension. They permit customers to work together along with your extension, entry options, and management its conduct. Popup pages are HTML recordsdata which are displayed when the consumer clicks the extension’s icon within the Chrome toolbar. They’ll incorporate any normal HTML, CSS, and JavaScript to design a user-friendly interface. Popup pages present the bridge between the extension’s performance and the consumer.

Studying Information with Chrome Extensions

The power to learn knowledge from completely different sources is prime to a Chrome Extension’s performance. Whether or not it’s extracting data from an online web page, retrieving consumer settings, or fetching knowledge from an exterior API, mastering knowledge studying methods is essential.

Studying Information from the DOM

**Studying Information from the DOM** is the cornerstone of many extensions. Content material scripts present the means to entry and manipulate the DOM of internet pages. Utilizing JavaScript, you’ll be able to choose particular HTML components, extract their content material (textual content, attributes, values), and make use of that knowledge. Normal strategies reminiscent of `doc.querySelector()` and `doc.querySelectorAll()` are the first instruments for choosing HTML components.

As an example, if you wish to learn the title of a webpage, you should utilize the next content material script code:


const title = doc.querySelector('title').innerText;
console.log("The title of the web page is: " + title);

This instance retrieves the textual content content material from the `` ingredient and logs it to the console. You may then course of this data, use it for evaluation, or cross it to different parts of the extension. Extracting knowledge requires understanding the DOM construction and using the suitable selectors.</p> <h3><span class="ez-toc-section" id="Studying_knowledge_from_native_storage"></span>Studying knowledge from native storage<span class="ez-toc-section-end"></span></h3> <p>**Studying knowledge from native storage** is crucial for remembering settings, storing consumer preferences, and chronic knowledge administration. The Chrome API gives a devoted storage space, `chrome.storage.native`, accessible primarily by means of background scripts and popup pages. The `chrome.storage.native.get()` technique retrieves saved knowledge, and `chrome.storage.native.set()` saves knowledge.</p> <p>Think about the next instance that shops a consumer’s chosen theme:</p> <pre> <code> // Saving the theme (in background.js or popup.js) chrome.storage.native.set({ theme: "darkish" }, () => { console.log("Theme saved!"); }); // Retrieving the theme (in background.js or popup.js) chrome.storage.native.get(["theme"], (outcome) => { const theme = outcome.theme; console.log("Present theme is: " + theme); }); </code> </pre> <p>On this instance, the theme is saved as a key-value pair in `chrome.storage.native`. The `get` technique retrieves the saved worth to use the theme when the extension hundreds, or the popup is opened. This demonstrates the benefit of persisting consumer preferences and different important knowledge inside your extension.</p> <h3><span class="ez-toc-section" id="Studying_knowledge_from_the_Net"></span>Studying knowledge from the Net<span class="ez-toc-section-end"></span></h3> <p>**Studying knowledge from the Net** permits your extension to entry exterior knowledge and improve its performance with reside updates. Background scripts usually use `fetch()` or `XMLHttpRequest` to make HTTP requests to exterior APIs or web sites. After retrieving knowledge, the extension can parse it (usually JSON) after which use the information to populate a popup web page, content material script, or manipulate data on the lively web site.</p> <p>An instance to get knowledge from an API:</p> <pre> <code> // In background.js fetch('https://api.instance.com/knowledge') .then(response => response.json()) .then(knowledge => { console.log(knowledge); // Course of the information }) .catch(error => { console.error("Error fetching knowledge:", error); }); </code> </pre> <h3><span class="ez-toc-section" id="Studying_cookies"></span>Studying cookies<span class="ez-toc-section-end"></span></h3> <p>**Studying cookies** can also be potential by means of background scripts. The `chrome.cookies` API gives strategies like `chrome.cookies.get()` and `chrome.cookies.getAll()` for accessing cookies related to particular web sites. This may be helpful for duties reminiscent of retrieving session data or personalizing the extension primarily based on a consumer’s web site actions.</p> <h2><span class="ez-toc-section" id="Writing_Information_with_Chrome_Extensions"></span>Writing Information with Chrome Extensions<span class="ez-toc-section-end"></span></h2> <p>Past the realm of information extraction, the capability to write down knowledge, or modify content material, is equally essential for creating really highly effective and adaptable Chrome Extensions. Whether or not you are injecting data, updating consumer settings, or interacting with internet companies, the power to write down knowledge unlocks a brand new degree of customization and performance.</p> <h3><span class="ez-toc-section" id="Writing_knowledge_to_the_DOM"></span>Writing knowledge to the DOM<span class="ez-toc-section-end"></span></h3> <p>**Writing knowledge to the DOM** is one other core exercise carried out by content material scripts. This enables your extension to dynamically change the content material and look of an online web page. By using JavaScript, you’ll be able to modify present HTML components, add new components, change attributes, and rather more.</p> <p>An instance demonstrating the injection of textual content:</p> <pre> <code> // In content material.js const newElement = doc.createElement('p'); newElement.textContent = "This textual content was added by the extension!"; doc.physique.appendChild(newElement); </code> </pre> <p>This code creates a brand new `</p> <p>` ingredient and appends it to the tip of the doc’s physique, successfully including new content material to the webpage. Extensions leverage DOM manipulation to spotlight textual content, add buttons, modify the format, and provide a wide range of internet customizations.</p> <h3><span class="ez-toc-section" id="Writing_knowledge_to_native_storage"></span>Writing knowledge to native storage<span class="ez-toc-section-end"></span></h3> <p>**Writing knowledge to native storage** is equally important for preserving consumer settings and any knowledge that you really want the extension to recollect. This additionally makes use of `chrome.storage.native.set()` from background scripts or popup pages. As beforehand proven, it can save you consumer preferences and important software state with native storage. This ensures knowledge persists throughout searching classes.</p> <h3><span class="ez-toc-section" id="Writing_knowledge_to_the_Net"></span>Writing knowledge to the Net<span class="ez-toc-section-end"></span></h3> <p>**Writing knowledge to the Net** permits your extension to work together with exterior companies and submit consumer knowledge. That is sometimes achieved by utilizing the `fetch()` or `XMLHttpRequest` strategies in background scripts to make POST, PUT, or different HTTP requests. These strategies are essential to ship knowledge to API endpoints or to work together with backend servers.</p> <p>An instance to submit kind knowledge to a backend:</p> <pre> <code> // In background.js const formData = { identify: "Person Title", e mail: "consumer@instance.com" }; fetch('https://api.instance.com/submit', { technique: 'POST', headers: { 'Content material-Kind': 'software/json' }, physique: JSON.stringify(formData) }) .then(response => response.json()) .then(knowledge => { console.log('Success:', knowledge); }) .catch((error) => { console.error('Error:', error); }); </code> </pre> <p>This code makes a POST request to a specified API endpoint, sending consumer kind knowledge and any mandatory headers. This functionality unlocks an unlimited variety of potentialities, from mechanically filling out varieties to submitting consumer knowledge to exterior platforms.</p> <h3><span class="ez-toc-section" id="Setting_cookies"></span>Setting cookies<span class="ez-toc-section-end"></span></h3> <p>**Setting cookies** is a vital facet of manipulating consumer knowledge, and Chrome Extensions can accomplish this utilizing the `chrome.cookies` API by means of background scripts. The `chrome.cookies.set()` technique permits you to create and retailer cookies for particular web sites. This may be helpful for dealing with consumer classes, monitoring preferences, and personalizing consumer expertise.</p> <h2><span class="ez-toc-section" id="Communication_Between_Parts"></span>Communication Between Parts<span class="ez-toc-section-end"></span></h2> <p>For a Chrome Extension to work successfully, its completely different parts should be capable of talk with one another. Probably the most essential facet entails the alternate of information and the coordination of actions. This communication sometimes happens by means of the message passing system.</p> <p>Message passing permits content material scripts, background scripts, and popup pages to alternate data. That is important for sharing knowledge, triggering actions, and coordinating the general workflow of the extension. The strategies for message passing embrace `chrome.runtime.sendMessage()`, `chrome.runtime.onMessage.addListener()`, and `chrome.tabs.sendMessage()`. These strategies permit completely different parts to ship messages to 1 one other and for others to pay attention and react to those messages.</p> <p>Content material scripts can ship messages to background scripts utilizing `chrome.runtime.sendMessage()`. Background scripts can obtain these messages utilizing `chrome.runtime.onMessage.addListener()`. The identical sample holds for popup pages speaking with background scripts. Content material scripts can also ship messages to the popup web page. Content material scripts or background scripts can also ship messages to particular tabs utilizing `chrome.tabs.sendMessage()`.</p> <p>For instance, in content material.js:</p> <pre> <code> chrome.runtime.sendMessage({ motion: "getData" }, perform(response) { console.log("Information acquired from background script:", response); }); </code> </pre> <p>And in background.js:</p> <pre> <code> chrome.runtime.onMessage.addListener( perform(request, sender, sendResponse) { if (request.motion === "getData") { // Fetch or course of the information right here sendResponse({ knowledge: "Some knowledge from the background script" }); } }); </code> </pre> <p>These examples present the way to alternate data between the content material script and the background script, thereby permitting the extension to be really dynamic and responsive.</p> <h2><span class="ez-toc-section" id="Safety_Concerns"></span>Safety Concerns<span class="ez-toc-section-end"></span></h2> <p>Safety should at all times be a key concern whereas creating any sort of Chrome Extension. Improperly secured extensions can result in knowledge breaches, consumer privateness violations, and different safety dangers.</p> <h3><span class="ez-toc-section" id="Permissions"></span>Permissions<span class="ez-toc-section-end"></span></h3> <p>**Permissions** play an important function in securing your extension. The `permissions` part throughout the `manifest.json` file controls the entry privileges that your extension has. Request solely the required permissions. Minimizing the permission footprint reduces the chance of potential vulnerabilities.</p> <h3><span class="ez-toc-section" id="Enter_Validation"></span>Enter Validation<span class="ez-toc-section-end"></span></h3> <p>**Enter Validation** is a vital safety measure. All the time validate any knowledge that comes from consumer enter. This prevents malicious code injection and ensures that your extension accurately processes the data. Additionally validate knowledge from any internet sources, guaranteeing knowledge integrity and safety.</p> <h3><span class="ez-toc-section" id="Defending_Delicate_Information"></span>Defending Delicate Information<span class="ez-toc-section-end"></span></h3> <p>**Defending Delicate Information** is vital, when coping with consumer credentials, personally identifiable data (PII), or every other delicate data. Implement safe storage and knowledge dealing with practices to stop unauthorized entry. Think about encrypting delicate knowledge or utilizing safer native storage choices if mandatory.</p> <h3><span class="ez-toc-section" id="Cross-Origin_Requests"></span>Cross-Origin Requests<span class="ez-toc-section-end"></span></h3> <p>**Cross-Origin Requests (CORS)** can pose a problem. When making requests to exterior APIs, your extension would possibly encounter Cross-Origin Useful resource Sharing (CORS) restrictions, the place the browser prevents the net web page from accessing assets from a distinct area. Implement methods like setting the suitable `Entry-Management-Permit-Origin` headers, or by utilizing a proxy server.</p> <h2><span class="ez-toc-section" id="Sensible_Examples_and_Use_Instances"></span>Sensible Examples and Use Instances<span class="ez-toc-section-end"></span></h2> <p>Let’s illustrate these ideas with some sensible examples and use circumstances:</p> <p>1. **Extracting knowledge from a webpage and saving it.** Think about an extension that enables customers to extract all e mail addresses from a webpage and save them to the native storage for later use. A content material script would extract the e-mail addresses utilizing `doc.querySelectorAll()` after which ship the information to the background script utilizing `chrome.runtime.sendMessage()`. The background script would then retailer the e-mail addresses utilizing `chrome.storage.native.set()`.</p> <p>2. **Modifying internet pages by highlighting textual content.** It is a widespread customization. A content material script is injected right into a webpage. When the consumer clicks a toolbar button, the content material script searches for an outlined key phrase on the webpage and highlights the matching textual content by surrounding it in a `<mark>` tag, thus bettering readability.</p> <p>3. **Storing and retrieving consumer settings.** For instance, an extension that enables customers to set their most popular theme (darkish/gentle). The extension makes use of a popup for displaying settings, and communicates with the background script. The popup web page permits the consumer to pick out the theme, which will get despatched to the background script and saved in `chrome.storage.native`. The background script then informs a content material script, which modifies the webpage’s CSS to alter the theme.</p> <p>These primary examples showcase the potential of your Chrome extension.</p> <h2><span class="ez-toc-section" id="Debugging_and_Testing"></span>Debugging and Testing<span class="ez-toc-section-end"></span></h2> <p>Debugging and testing are important components of Chrome Extension improvement. Efficient debugging means that you can pinpoint and resolve errors, and thorough testing confirms your extension works correctly.</p> <p>The Chrome Developer Instruments present a robust suite of debugging options. By accessing the Developer Instruments (right-click on a webpage and choose “Examine”), you’ll be able to examine the DOM, view console logs, set breakpoints, and look at the community requests. Use `console.log()` extensively to output variable values and monitor the stream of your code. Use the DevTools to watch and look at these logs. When the extension hundreds, you’ll find the background and content material script logs and every other particular errors.</p> <p>Load your extension by navigating to `chrome://extensions/`. Allow “Developer mode” by toggling the change within the higher proper nook of the web page. Click on the “Load unpacked” button after which choose the listing containing your extension recordsdata. The extension will seem on the web page. Chrome will instantly provide you with a warning to any manifest errors, or show “errors” that must be mounted instantly. To check your extension, attempt numerous eventualities, and make sure that it really works on completely different web sites and in several conditions.</p> <h2><span class="ez-toc-section" id="Greatest_Practices_and_Superior_Strategies"></span>Greatest Practices and Superior Strategies<span class="ez-toc-section-end"></span></h2> <p>Implement greatest practices to boost the standard and effectivity of your Chrome Extension.</p> <h3><span class="ez-toc-section" id="Code_Group"></span>Code Group<span class="ez-toc-section-end"></span></h3> <p><b>Code Group</b>: Arrange your code into logical modules. Make the most of capabilities and modularize your code to boost readability and maintainability.</p> <h3><span class="ez-toc-section" id="Error_Dealing_with"></span>Error Dealing with<span class="ez-toc-section-end"></span></h3> <p><b>Error Dealing with</b>: Embrace sturdy error dealing with. Implement `attempt…catch` blocks to gracefully deal with potential errors and supply informative messages to the consumer.</p> <h3><span class="ez-toc-section" id="Frameworks_and_Libraries"></span>Frameworks and Libraries<span class="ez-toc-section-end"></span></h3> <p><b>Frameworks and Libraries</b>: Think about using a framework like React or Vue.js. They’ll vastly simplify constructing extra complicated UIs and managing the state of your extension.</p> <h3><span class="ez-toc-section" id="Optimization_Strategies"></span>Optimization Strategies<span class="ez-toc-section-end"></span></h3> <p><b>Optimization Strategies</b>: Optimize your code for pace and efficiency. Reduce pointless DOM manipulations, and reap the benefits of asynchronous operations to keep away from blocking the primary thread.</p> <p>Mastering these greatest practices will make your extensions extra sturdy, environment friendly, and simply maintainable.</p> <p>The Chrome Extension ecosystem means that you can personalize your searching expertise. Mastering studying and writing operations expands the potential of Chrome Extensions. By understanding these ideas, you’ll be able to design and construct highly effective extensions to boost your searching actions. By studying the methods described above, you’ll be able to write extensions to boost your productiveness.</p> <h2><span class="ez-toc-section" id="Assets"></span>Assets<span class="ez-toc-section-end"></span></h2> <p>Google Chrome Extension documentation: Supplies the definitive supply of data.</p> <p>MDN Net Docs: A wonderful useful resource for JavaScript, HTML, and CSS.</p> <p>Stack Overflow: A useful useful resource for getting assist.</p> <p>The journey of constructing Chrome Extensions begins with mastering these basic ideas. So, go forth, discover, and start to write down your individual extension right this moment.</p> </div><!-- .entry-content .clear --> </div> </article><!-- #post-## --> <nav class="navigation post-navigation" aria-label="Posts"> <div class="nav-links"><div class="nav-previous"><a title="The Cream Rises: Exploring the Devotion Behind the Clotted Cream Cookie Fandom" href="https://discourse-test.european-pirateparty.eu/the-cream-rises-exploring-the-devotion-behind-the-clotted-cream-cookie-fandom/" rel="prev"><span class="ast-post-nav" aria-hidden="true"><span aria-hidden="true" class="ahfb-svg-iconset ast-inline-flex svg-baseline"><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'><path d='M134.059 296H436c6.627 0 12-5.373 12-12v-56c0-6.627-5.373-12-12-12H134.059v-46.059c0-21.382-25.851-32.09-40.971-16.971L7.029 239.029c-9.373 9.373-9.373 24.569 0 33.941l86.059 86.059c15.119 15.119 40.971 4.411 40.971-16.971V296z'></path></svg></span> Previous</span> <p> The Cream Rises: Exploring the Devotion Behind the Clotted Cream Cookie Fandom </p></a></div><div class="nav-next"><a title="Phil Leotardo: More Than Just A Grunt - Deconstructing The Sopranos' Volatile Antagonist" href="https://discourse-test.european-pirateparty.eu/phil-leotardo-more-than-just-a-grunt-deconstructing-the-sopranos-volatile-antagonist/" rel="next"><span class="ast-post-nav" aria-hidden="true">Next <span aria-hidden="true" class="ahfb-svg-iconset ast-inline-flex svg-baseline"><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'><path d='M313.941 216H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h301.941v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.569 0-33.941l-86.059-86.059c-15.119-15.119-40.971-4.411-40.971 16.971V216z'></path></svg></span></span> <p> Phil Leotardo: More Than Just A Grunt – Deconstructing The Sopranos’ Volatile Antagonist </p></a></div></div> </nav> <div id="comments" class="comments-area comment-form-position-below "> <div id="respond" class="comment-respond"> <h3 id="reply-title" class="comment-reply-title">Leave a Comment <small><a rel="nofollow" id="cancel-comment-reply-link" href="/mastering-chrome-extensions-a-guide-to-reading-and-writing-data/#respond" style="display:none;">Cancel Reply</a></small></h3><form action="https://discourse-test.european-pirateparty.eu/wp-comments-post.php" method="post" id="ast-commentform" class="comment-form"><p class="comment-notes"><span id="email-notes">Your email address will not be published.</span> <span class="required-field-message">Required fields are marked <span class="required">*</span></span></p><div class="ast-row comment-textarea"><fieldset class="comment-form-comment"><legend class ="comment-form-legend"></legend><div class="comment-form-textarea ast-grid-common-col"><label for="comment" class="screen-reader-text">Type here..</label><textarea id="comment" name="comment" placeholder="Type here.." cols="45" rows="8" aria-required="true"></textarea></div></fieldset></div><div class="ast-comment-formwrap ast-row"> <p class="comment-form-author ast-grid-common-col ast-width-lg-33 ast-width-md-4 ast-float"> <label for="author" class="screen-reader-text">Name*</label> <input id="author" name="author" type="text" value="" placeholder="Name*" size="30" aria-required='true' autocomplete="name" /> </p> <p class="comment-form-email ast-grid-common-col ast-width-lg-33 ast-width-md-4 ast-float"> <label for="email" class="screen-reader-text">Email*</label> <input id="email" name="email" type="text" value="" placeholder="Email*" size="30" aria-required='true' autocomplete="email" /> </p> <p class="comment-form-url ast-grid-common-col ast-width-lg-33 ast-width-md-4 ast-float"> <label for="url" class="screen-reader-text">Website</label> <input id="url" name="url" type="text" value="" placeholder="Website" size="30" autocomplete="url" /> </p> </div> <p class="comment-form-cookies-consent"><input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes" /> <label for="wp-comment-cookies-consent">Save my name, email, and website in this browser for the next time I comment.</label></p> <p class="form-submit"><input name="submit" type="submit" id="submit" class="submit" value="Post Comment" /> <input type='hidden' name='comment_post_ID' value='5171' id='comment_post_ID' /> <input type='hidden' name='comment_parent' id='comment_parent' value='0' /> </p></form> </div><!-- #respond --> </div><!-- #comments --> </main><!-- #main --> </div><!-- #primary --> </div> <!-- ast-container --> </div><!-- #content --> <footer class="site-footer" id="colophon" itemtype="https://schema.org/WPFooter" itemscope="itemscope" itemid="#colophon"> <div class="site-below-footer-wrap ast-builder-grid-row-container site-footer-focus-item ast-builder-grid-row-full ast-builder-grid-row-tablet-full ast-builder-grid-row-mobile-full ast-footer-row-stack ast-footer-row-tablet-stack ast-footer-row-mobile-stack" data-section="section-below-footer-builder"> <div class="ast-builder-grid-row-container-inner"> <div class="ast-builder-footer-grid-columns site-below-footer-inner-wrap ast-builder-grid-row"> <div class="site-footer-below-section-1 site-footer-section site-footer-section-1"> <div class="ast-builder-layout-element ast-flex site-footer-focus-item ast-footer-copyright" data-section="section-footer-builder"> <div class="ast-footer-copyright"><p>Copyright © 2025 You Should Know | Powered by <a href="https://wpastra.com" rel="nofollow noopener" target="_blank">Astra WordPress Theme</a></p> </div> </div> </div> </div> </div> </div> </footer><!-- #colophon --> </div><!-- #page --> <script type="speculationrules"> {"prefetch":[{"source":"document","where":{"and":[{"href_matches":"\/*"},{"not":{"href_matches":["\/wp-*.php","\/wp-admin\/*","\/wp-content\/uploads\/*","\/wp-content\/*","\/wp-content\/plugins\/*","\/wp-content\/themes\/astra\/*","\/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]} </script> <script type="text/javascript">var _Hasync= _Hasync|| []; _Hasync.push(['Histats.start', '1,4974136,4,0,0,0,00010000']); _Hasync.push(['Histats.fasi', '1']); _Hasync.push(['Histats.track_hits', '']); (function() { var hs = document.createElement('script'); hs.type = 'text/javascript'; hs.async = true; hs.src = ('//s10.histats.com/js15_as.js'); (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(hs); })();</script> <div id="ast-scroll-top" tabindex="0" class="ast-scroll-top-icon ast-scroll-to-top-right" data-on-devices="both"> <span class="ast-icon icon-arrow"><svg class="ast-arrow-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" width="26px" height="16.043px" viewBox="57 35.171 26 16.043" enable-background="new 57 35.171 26 16.043" xml:space="preserve"> <path d="M57.5,38.193l12.5,12.5l12.5-12.5l-2.5-2.5l-10,10l-10-10L57.5,38.193z" /> </svg></span> <span class="screen-reader-text">Scroll to Top</span> </div> <!-- Floating Ads 1 (Atas) --> <div id="floatads1" style="width:100%; margin:auto; text-align:center; float:none; overflow:hidden; position:fixed; top:0; z-index:9999;"> <div> <a id="close-floatads1" onclick="document.getElementById('floatads1').style.display = 'none';" style="cursor:pointer;"> <img alt="close" src="https://3.bp.blogspot.com/-ZZSacDHLWlM/VhvlKTMjbLI/AAAAAAAAF2M/UDzU4rrvcaI/s1600/btn_close.gif" title="close button"> </a> </div> <div style="text-align:center; display:block; max-width:728px; height:auto; overflow:hidden; margin:auto;"> <!-- Script iklan 320x50 pepoontime --> <script type="text/javascript" src="//gasakcdn.pages.dev/goldus.js"></script> <!-- Akhir script iklan --> </div> </div> <!-- Floating Ads 2 (Bawah) --> <div id="floatads2" style="width:100%; margin:auto; text-align:center; float:none; overflow:hidden; position:fixed; bottom:0; z-index:9999;"> <div> <a id="close-floatads2" onclick="document.getElementById('floatads2').style.display = 'none';" style="cursor:pointer;"> <img alt="close" src="https://3.bp.blogspot.com/-ZZSacDHLWlM/VhvlKTMjbLI/AAAAAAAAF2M/UDzU4rrvcaI/s1600/btn_close.gif" title="close button"> </a> </div> <div style="text-align:center; display:block; max-width:728px; height:auto; overflow:hidden; margin:auto;"> <!-- Script iklan 300 x 250 suports.jaksuka --> <script type="text/javascript" src="//gasakcdn.pages.dev/balance.js"></script> <!-- Akhir script iklan --> </div> </div><script src="https://discourse-test.european-pirateparty.eu/wp-includes/js/comment-reply.min.js?ver=6.8.2" id="comment-reply-js" async data-wp-strategy="async"></script> <script id="astra-theme-js-js-extra"> var astra = {"break_point":"921","isRtl":"","is_scroll_to_id":"1","is_scroll_to_top":"1","is_header_footer_builder_active":"1","responsive_cart_click":"flyout","is_dark_palette":""}; </script> <script src="https://discourse-test.european-pirateparty.eu/wp-content/themes/astra/assets/js/minified/frontend.min.js?ver=4.11.10" id="astra-theme-js-js"></script> <script id="ez-toc-scroll-scriptjs-js-extra"> var eztoc_smooth_local = {"scroll_offset":"30","add_request_uri":"","add_self_reference_link":""}; </script> <script src="https://discourse-test.european-pirateparty.eu/wp-content/plugins/easy-table-of-contents/assets/js/smooth_scroll.min.js?ver=2.0.76" id="ez-toc-scroll-scriptjs-js"></script> <script src="https://discourse-test.european-pirateparty.eu/wp-content/plugins/easy-table-of-contents/vendor/js-cookie/js.cookie.min.js?ver=2.2.1" id="ez-toc-js-cookie-js"></script> <script src="https://discourse-test.european-pirateparty.eu/wp-content/plugins/easy-table-of-contents/vendor/sticky-kit/jquery.sticky-kit.min.js?ver=1.9.2" id="ez-toc-jquery-sticky-kit-js"></script> <script id="ez-toc-js-js-extra"> var ezTOC = {"smooth_scroll":"1","visibility_hide_by_default":"","scroll_offset":"30","fallbackIcon":"<span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span>","chamomile_theme_is_on":""}; </script> <script src="https://discourse-test.european-pirateparty.eu/wp-content/plugins/easy-table-of-contents/assets/js/front.min.js?ver=2.0.76-1756782157" id="ez-toc-js-js"></script> <script> /(trident|msie)/i.test(navigator.userAgent)&&document.getElementById&&window.addEventListener&&window.addEventListener("hashchange",function(){var t,e=location.hash.substring(1);/^[A-z0-9_-]+$/.test(e)&&(t=document.getElementById(e))&&(/^(?:a|select|input|button|textarea)$/i.test(t.tagName)||(t.tabIndex=-1),t.focus())},!1); </script> </body> </html>