<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Tomer Weller / Blob</title>
    <description>an indeterminate mass or shape</description>
    <link>https://tomerweller.com/</link>
    <atom:link href="https://tomerweller.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Mon, 24 Aug 2026 17:57:13 +0000</pubDate>
    <lastBuildDate>Mon, 24 Aug 2026 17:57:13 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
     
      <item>
        <title>ESP32 - first steps</title>
        <description>&lt;p&gt;This post describes my first steps with ESP32. It was originally written as preparation for TA’ing communications week in MIT’s &lt;a href=&quot;http://fab.cba.mit.edu/classes/863.16/&quot;&gt;fabclass&lt;/a&gt;. I cover basic setup, firmware deployment and a hint of benchmarking.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Warning: This post was written in November 2016. ESP32 is brand spanking new and should be considered a moving target&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contents:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#what-is-the-esp32&quot;&gt;What is the ESP32?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#hardware-setup&quot;&gt;Hardware Setup&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#equipment-used&quot;&gt;Equipment Used&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#basic-connectivity&quot;&gt;Basic Connectivity&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#sanity-check&quot;&gt;Sanity Check&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#programming&quot;&gt;Programming&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#freertos&quot;&gt;FreeRTOS&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#esp---idf&quot;&gt;ESP - IDF&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#esp32-arduino-core&quot;&gt;ESP32 ARDUINO CORE&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#ring-oscillator-benchmark&quot;&gt;Ring Oscillator benchmark&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#more-resources&quot;&gt;More Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;what-is-the-esp32&quot;&gt;What is the ESP32?&lt;/h3&gt;

&lt;p&gt;ESP32, successor to the beloved ESP8266, is system on a chip (SoC) that can do (almost) anything:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Real concurrency with two cores&lt;/li&gt;
  &lt;li&gt;WIFI&lt;/li&gt;
  &lt;li&gt;Bluetooth&lt;/li&gt;
  &lt;li&gt;BLE&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://espressif.com/en/products/hardware/esp32/overview&quot;&gt;Much more&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/esp32/esp32-arch.jpg&quot; alt=&quot;esp32-arch&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Espressif, the manufacturer, have been kind enough to send some units of their new ESP32 modules for evaluation. (huge thanks to John Lee &lt;a href=&quot;https://twitter.com/EspressifSystem&quot;&gt;@EspressifSystem&lt;/a&gt;) I will demonstrate basic connectivity, different ways to program it, and basic benchmarking.&lt;/p&gt;

&lt;h3 id=&quot;hardware-setup&quot;&gt;Hardware Setup&lt;/h3&gt;

&lt;h4 id=&quot;equipment-used&quot;&gt;Equipment Used&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://espressif.com/en/producttype/esp-wroom-32&quot;&gt;&lt;strong&gt;ESP32 WROOM32&lt;/strong&gt;&lt;/a&gt; module. This is Espressif’s own ESP32 module. It’s safe to assume that we’ll see ESP32 used in modules from 3rd party manufacturers in the near future (AI was the lead module manufacturer for the ESP8266).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ESP32 Breakout&lt;/strong&gt; board. Espressif provided us with &lt;a href=&quot;/assets/esp32/esp32-breakout.png&quot;&gt;simple breakout boards&lt;/a&gt; that expose all I/O pins and physical buttons for RESET and BOOT MODE.
There are other boards available to order as well as designs to &lt;a href=&quot;https://github.com/a2retro/ESP32_Miscellany&quot;&gt;mill your own&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;FTDI Cable&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;3.3V Power Supply&lt;/strong&gt; (up to 500mA). DO NOT USE THE FTDI POWER - IT CAN’T PROVIDE ENOUGH CURRENT. (TRUST ME - I’VE TRIED)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: soldering the module to the breakout board proved non-trivial, the ground plane is very large so a high wattage soldering iron is recommended for soldering the ground pads.&lt;/em&gt;&lt;/p&gt;

&lt;h4 id=&quot;basic-connectivity&quot;&gt;Basic Connectivity&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/assets/esp32/esp32-pinout.png&quot; alt=&quot;esp32-pinout&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;VCC (ESP32) -&amp;gt; 3.3V (POWER)&lt;/li&gt;
  &lt;li&gt;GND (ESP32) -&amp;gt; GND (POWER)&lt;/li&gt;
  &lt;li&gt;GND (ESP32) -&amp;gt; GND (FTDI)&lt;/li&gt;
  &lt;li&gt;TX (ESP32) -&amp;gt; RX (FTDI)&lt;/li&gt;
  &lt;li&gt;RX (ESP32) -&amp;gt; TX (FTDI)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/esp32/esp32-basic-connectivity.png&quot; alt=&quot;esp32-pinout&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;sanity-check&quot;&gt;Sanity Check&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;Open a terminal emulator on the FTDI port with a BAUD rate of 115200&lt;/li&gt;
  &lt;li&gt;Hit the RESET button&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;⇒  miniterm.py /dev/tty.usbserial-XXXXXXXX 115200
ets Jun  8 2016 00:22:57
rst:0x1 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;POWERON_RESET&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,boot:0x13 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;SPI_FAST_FLASH_BOOT&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
....
IDF version : master&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;db93bceb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
WIFI LIB version : master&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;934d079b&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
ssc version : master&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;r283 4d376412&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;!!!&lt;/span&gt;ready!!!
mode : softAP&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;26:0a:c4:00:27:f4&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
dhcp server start:&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ip: 192.168.4.1, mask: 255.255.255.0, gw: 192.168.4.1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
+WIFI:AP_START&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Not only does it work, it even defaults to opening a public access point&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;⇒  airport &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;ESP
ESP_0027F4 26:0a:c4:00:27:f4 &lt;span class=&quot;nt&quot;&gt;-14&lt;/span&gt;  1,+1    Y  &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; NONE
When a device enters the network:
n:1 0, o:1 0, ap:1 1, sta:255 255, prof:1
add 1
station: 80:e6:50:27:b6:62 &lt;span class=&quot;nb&quot;&gt;join&lt;/span&gt;, AID &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 1, g, 20
+SOFTAP:STACONNECTED,80:e6:50:27:b6:62&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I couldn’t find any other interesting things in the provided firmware.
In case you were wondering, like me, whether ESP8266’s &lt;a href=&quot;https://www.itead.cc/wiki/ESP8266_Serial_WIFI_Module&quot;&gt;AT command-set&lt;/a&gt; works in this prompt, the answer is no. It’s not very clear what commands do work here. (If you know of some, leave them in the comments below)&lt;/p&gt;

&lt;h3 id=&quot;programming&quot;&gt;Programming&lt;/h3&gt;

&lt;h4 id=&quot;freertos&quot;&gt;FreeRTOS&lt;/h4&gt;

&lt;p&gt;Before programming this chip it’s crucial to understand that, unlike other embedded systems, the ESP32 comes with a light operating system - &lt;a href=&quot;http://www.freertos.org/&quot;&gt;FreeRTOS&lt;/a&gt;. The following methods to program this chip don’t replace the FreeRTOS firmware, but rather deploy applications for it to run. I imagine that in the near future we’ll see other operating systems or no-os approaches for reprogramming these chips.&lt;/p&gt;

&lt;p&gt;There are currently two methods to program the ESP32: the ESP-IDF and the ESP32 arduino Core.&lt;/p&gt;

&lt;h4 id=&quot;esp---idf&quot;&gt;ESP - IDF&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/espressif/esp-idf&quot;&gt;Espressif IoT Development Framework&lt;/a&gt; is a set of open source libraries and tools to facilitate deployment of apps to ESP32s FreeRTOS.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/tomerweller/esp32-rtos-webclient&quot;&gt;Code Example : HTTP GET request using the ESP IDF&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;esp32-arduino-core&quot;&gt;ESP32 ARDUINO CORE&lt;/h4&gt;

&lt;p&gt;Espressif have also been hard at work to get the maker community happy and makers love Arduino. The &lt;a href=&quot;https://github.com/espressif/arduino-esp32&quot;&gt;ESP32 arduino core&lt;/a&gt; integrates ESP-IDF deeply into the arduino tools. This includes providing a WiFi API that is almost 100% compatible with existing wifi shields for arduino.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/tomerweller/esp32-arduino-webclient&quot;&gt;Code Example : HTTP GET request using the ESP32 Arduino Core&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: currently, to take advantage of the concurrency capabilities - IDF is the way to go.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;ring-oscillator-benchmark&quot;&gt;Ring Oscillator benchmark&lt;/h3&gt;
&lt;p&gt;Ring oscillator tests measure the minimal amount of time it takes for a signal to get out of a chip and back through peripherals.&lt;/p&gt;

&lt;p&gt;In practice, it means shorting two pins with a jumper, defining one as input and the other as output, and then writing and reading as fast as possible. The result is recorded with an oscilloscope connected to the shortened pins and ground.&lt;/p&gt;

&lt;p&gt;Here, I measure both programming methods mentioned earlier:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;FreeRTOS &lt;a href=&quot;https://gist.github.com/tomerweller/7f9f202858cb064c84722c72f6c20aee&quot;&gt;(code)&lt;/a&gt;&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Arduino Core &lt;a href=&quot;https://gist.github.com/tomerweller/e50403bb18dcb6932d54e8f11edf0734&quot;&gt;(code)&lt;/a&gt;&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;/assets/esp32/esp32-ro-freertos.jpg&quot; alt=&quot;rtos-ro&quot; /&gt;1.63MHz&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;/assets/esp32/esp32-ro-core.jpg&quot; alt=&quot;core-ro&quot; /&gt;1.05MHz&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt; the Arduino program is about 35% slower than the lower level FreeRTOS program. However, usually in these type of tests, the portability of arduino code comes with a much bigger performance drop. Good job, Espressif!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: These tests only occupy one core. The second core is free to perform other tasks, such as networking. &lt;a href=&quot;https://github.com/tomerweller/esp32-rtos-webclient/tree/with-ring-oscillator&quot;&gt;Example&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;more-resources&quot;&gt;More Resources&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf&quot;&gt;ESP32 Data Sheet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://espressif.com/sites/default/files/documentation/esp_wroom_32_datasheet_en.pdf&quot;&gt;ESP-WROOM32 Data Sheet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.esp32.com/&quot;&gt;ESP32 official forum&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://hackaday.com/2016/10/04/how-to-get-started-with-the-esp32&quot;&gt;ESP32 Getting started (hackaday)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;thanks&quot;&gt;Thanks:&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/EspressifSystem&quot;&gt;John Lee&lt;/a&gt; and espressif for providing the hardware.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/achituv&quot;&gt;Tal Achituv&lt;/a&gt; for help with soldering and the oscilloscope.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://jonathanbobrow.com/&quot;&gt;Jonathan Bobrow&lt;/a&gt; for feedback on this post.&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Mon, 09 Jan 2017 01:00:00 +0000</pubDate>
        <link>https://tomerweller.com/blob/esp32-first-steps</link>
        <guid isPermaLink="true">https://tomerweller.com/blob/esp32-first-steps</guid>
        
        
      </item>
     
      <item>
        <title>Clojurescript/Reagent : importing React components from NPM</title>
        <description>&lt;p&gt;This post describes, step by step, how to setup a workflow for importing &lt;a href=&quot;https://facebook.github.io/react/&quot;&gt;React&lt;/a&gt; components from &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;NPM&lt;/a&gt;, using &lt;a href=&quot;https://webpack.github.io/&quot;&gt;Webpack&lt;/a&gt;, and incorporate them in your &lt;a href=&quot;https://reagent-project.github.io/&quot;&gt;Reagent&lt;/a&gt; views.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPDATE (June 17th, 2017): A year later, this post and method are very much still relevant. I’ve made a small update to take advantage of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:foreign-libs&lt;/code&gt; option, as suggested in the comments (Thanks Andreas and Alex!), which reduces the plumbing necessary.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;motivation&quot;&gt;Motivation&lt;/h3&gt;
&lt;p&gt;Any Javascript developer using a modern build tool can easily test and incorporate React components from 3rd party developers in their app. It’s usually just a matter of declaring dependencies, building and importing.&lt;/p&gt;

&lt;p&gt;Moving to Clojurescript and Reagent has been amazing in many ways but I just couldn’t wrap my head around a comparable import flow.&lt;/p&gt;

&lt;p&gt;The workflow I will describe employs NPM as a dependency manager and Webpack as a build tool. The build artifact is added as an external Javascript dependency to an otherwise (pretty) standard Leinnnigen build process.&lt;/p&gt;

&lt;p&gt;This solution does not use Cljsjs in anyway.&lt;/p&gt;

&lt;h3 id=&quot;why-not-cljsjs&quot;&gt;Why not Cljsjs?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://cljsjs.github.io/&quot;&gt;Cljsjs&lt;/a&gt; is a great community effort to package common Javascript libraries in a Clojurescript friendly way. However, it has some shortcomings.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Very few packages compared to NPM or Bower. Whenever I look for something it’s usually not there.&lt;/li&gt;
  &lt;li&gt;Packages are mostly &lt;a href=&quot;https://docs.google.com/spreadsheets/d/1t61hPgEfb1ukzezb6dn38z8kp07TsEFgkaVwF01-acE/pubhtml&quot;&gt;out of date&lt;/a&gt; compared to their NPM counterparts. This make sense because with NPM packages the author/maintainer of the library is the same person as the maintainer of the package. That’s not the case with Cljsjs.&lt;/li&gt;
  &lt;li&gt;Packaging a library is not trivial. The community’s usual reply to the import issue is “just package it yourself”. Sending someone who wants to fiddle around with a 3rd party react component, to package the dependency themselves is, in my opinion, cumbersome. This also leads back to problem #2.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;zefstyle&quot;&gt;Zefstyle&lt;/h3&gt;

&lt;p&gt;In this example we’ll start with a simple frontend-only Reagant app and setup a workflow that will allow us to add a &lt;a href=&quot;https://www.npmjs.com/package/react-player&quot;&gt;react-player&lt;/a&gt; component to it. Let’s call this project &lt;strong&gt;Zefstyle&lt;/strong&gt;. You can also skip this altogether and just jump to the finished result &lt;a href=&quot;https://github.com/tomerweller/zefstyle&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Starting with a template:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;lein new reagent-frontend zefstyle &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;zefstyle&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For sanity - Let’s see that it’s working&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;lein figwheel&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;While that’s running, open public/index.html in your favorite browser. You should see a page that says “Welcome to Reagent”&lt;/p&gt;

&lt;p&gt;Since we’re running figwheel, we can change that live. In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public/index.html&lt;/code&gt; change the header to “Zef Style” - You should see it updating within seconds. You can then close fihghweel for now.&lt;/p&gt;

&lt;h3 id=&quot;npm-setup&quot;&gt;NPM Setup&lt;/h3&gt;
&lt;p&gt;Let’s create a minimal &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file. We can either do it interactively with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm init&lt;/code&gt; or just manually create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;zefstyle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0.0.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;tomer.weller@gmail.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;watch&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;webpack -d --watch&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;webpack -p&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;react&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;15.5.4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;react-dom&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;15.5.4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;webpack&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.13.1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;react-player&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0.18.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;packagejson-remarks&quot;&gt;package.json remarks:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;We import &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;react&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;react-dom&lt;/code&gt; although they are not a hard dependency of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;react-player&lt;/code&gt; and more than that - we already have a React instance in our code, the one that Reagant depends on. Why? There is an order of execution issue when relying on Reagant’s React dependency. This also means that we will later need to exclude Reagant’s React dependency so that we don’t have two React instances.&lt;/li&gt;
  &lt;li&gt;I’ve included some shortcuts for webpack scripts. They are not necessary but will come in handy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install dependencies:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;All of our dependency tree should now be in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;An alternative approach to this step would be to use the &lt;a href=&quot;https://github.com/RyanMcG/lein-npm&quot;&gt;lein-npm&lt;/a&gt; plugin. I’m pretty comfortable with npm so I decided to do it myself.&lt;/p&gt;

&lt;h3 id=&quot;webpack-setup&quot;&gt;Webpack setup&lt;/h3&gt;
&lt;p&gt;Our webpack setup will be pretty minimal - no fancy loaders. It consists of a definition file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack.config.js&lt;/code&gt; and an entry script that bootstraps our imported libraries to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack.config.js&lt;/code&gt; :&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;webpack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;webpack&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BUILD_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;APP_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;APP_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/main.js`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BUILD_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;bundle.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We basically defined our entry point script as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/js/main.js&lt;/code&gt; and our output artifact as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public/js/bundle.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our entry &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/js/main.js&lt;/code&gt; should look something like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;deps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;react&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;react&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;react-dom&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;react-dom&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;react-player&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;react-player&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;React&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;deps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;react&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ReactDOM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;deps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;react-dom&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I usually prefer not to bind too many objects to the global window context, that’s why I push whatever I can into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window.deps&lt;/code&gt;. With that said, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;React&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReactDOM&lt;/code&gt; must be on the global window context because that’s where components expect them to be.&lt;/p&gt;

&lt;p&gt;Now we can either run&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm run build &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For a onetime build, or:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm run watch&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For a continuous build that watches for changes in our code. Given that the Javascript code should remain pretty static the watch might be redundant.&lt;/p&gt;

&lt;h3 id=&quot;leiningen-project-setup&quot;&gt;Leiningen project setup&lt;/h3&gt;
&lt;p&gt;Like I mentioned before, we’re counting on webpack to bring React into the picture. That means that we need to get rid of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cljsjs.react&lt;/code&gt; &amp;amp; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cljsjs.react.dom&lt;/code&gt; packages that reagant depends on.&lt;/p&gt;

&lt;p&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;project.clj&lt;/code&gt; let’s change our dependencies to be:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;no&quot;&gt;:dependencies&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;org.clojure/clojure&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.8.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:scope&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;provided&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;org.clojure/clojurescript&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.9.562&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:scope&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;provided&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reagent&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0.6.2&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:exclusions&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cljsjs/react&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cljsjs/react-dom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And add an external dependency to our webpack generated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle.js&lt;/code&gt; through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:foreign-libs&lt;/code&gt;. We need to add the following to all build profiles:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;no&quot;&gt;:foreign-libs&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;public/js/bundle.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:provides&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cljsjs.react&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cljsjs.react.dom&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;webpack.bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Notice how our foreign lib satisfies all react dependencies and also add a convenience namespace, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack.bundle&lt;/code&gt;, for importing the external bundle.&lt;/p&gt;

&lt;p&gt;At this point it’s a good idea to cleanup and re-run figwheel.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;lein clean &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; lein figwheel&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;grand-finale&quot;&gt;Grand finale&lt;/h3&gt;

&lt;p&gt;Now that we have everything in place we can add the react-player to our main Reagant view.&lt;/p&gt;

&lt;p&gt;in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/zefstyle/core.cljs&lt;/code&gt; let’s add the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webpack.bundle&lt;/code&gt; dependency to our namespace:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;ns zefstyle.core
  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;:require &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;reagent.core :as reagent :refer &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;atom]]
            &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;webpack.bundle]&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and change our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;home-page&lt;/code&gt; function to be:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;home-page&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;react-player&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;aget&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;js/window&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;deps&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;react-player&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:div&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:h2&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Zef Style&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;react-player&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:url&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://youtu.be/uMK0prafzw0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]]))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Notice the special &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&amp;gt;&lt;/code&gt; syntax for using pure React components.&lt;/p&gt;

&lt;p&gt;opening &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public/index.html&lt;/code&gt; should yield something like this: 
&lt;img src=&quot;/assets/zefstyle.png&quot; alt=&quot;yolandi&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Voila!&lt;/strong&gt; We brought the pure JS &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;react-player&lt;/code&gt; component into our Reagent view.&lt;/p&gt;

&lt;p&gt;To bring in new components we just need to declare them in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require()&lt;/code&gt; them in main.js and rebuild.&lt;/p&gt;

&lt;h3 id=&quot;caveats&quot;&gt;Caveats:&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;JS dependencies are not processed by the Closure compiler so they do not get advanced optimization, only whatever webpack is setup to do.&lt;/li&gt;
  &lt;li&gt;Setting up this process is not trivial. However, it only needs to be done once and from then on it’s a smooth sail. Also, automating the process or part of it sounds like a feasible task as part of a lein plugin. I’ll look into that when some time frees up.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let me know if this was helpful, requires some fixups or if it’s complete rubbish.&lt;/p&gt;

&lt;h3 id=&quot;thanks-to&quot;&gt;Thanks to:&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/trq__&quot;&gt;Thariq Shihipar&lt;/a&gt; for suggesting this approach although condemning the use of anything other than Javascript and React.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/clojurescript&quot;&gt;/r/clojurescript&lt;/a&gt;, &lt;a href=&quot;https://clojurians.slack.com&quot;&gt;Clojurians on Slack&lt;/a&gt; and especially @sbmitchell for helping me troubleshoot.&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Sat, 25 Jun 2016 04:59:59 +0000</pubDate>
        <link>https://tomerweller.com/blob/reagent-import-react-components-from-npm</link>
        <guid isPermaLink="true">https://tomerweller.com/blob/reagent-import-react-components-from-npm</guid>
        
        
      </item>
     
      <item>
        <title>Setting up a free live streaming solution in two hours</title>
        <description>&lt;h6 id=&quot;note-a-previous-version-of-this-post-had-some-licensing-terminology-issues-this-post-discusses-free-software&quot;&gt;Note: a previous version of this post had some licensing terminology issues. This post discusses Free software.&lt;/h6&gt;

&lt;p&gt;Last Sunday the Media Lab hosted a Public Dialogue on DRM and the future of the Web. Amongst the speakers was &lt;a href=&quot;https://stallman.org/&quot;&gt;Richard Stallman&lt;/a&gt; (aka &lt;strong&gt;RMS&lt;/strong&gt;), founder of the Free Software Foundation.  Although there was a lot of interest in the event from outside of the media lab, it couldn’t be streamed with MIT’s setup even though it was being filmed. MIT’s video streaming service is proprietary and Stallman will not use, or even take part in using, software that is not &lt;em&gt;completely&lt;/em&gt; free.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/free-streaming/the-panel.jpg&quot; alt=&quot;The Panel&quot; title=&quot;this is a title&quot; /&gt;
&lt;small&gt;Richard Stallman, Danny O’Brien, Joi Ito, and Harry Halpin. Photo: Jon Christian&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Earlier that day, during a lunch hosted by &lt;a href=&quot;http://joi.ito.com/&quot;&gt;Joi Ito&lt;/a&gt;, Tal Achituv and myself toyed with the idea of deploying a WebRTC based solution that is free and will be approved by RMS. After doing some research, it seemed that there are indeed free WebRTC options for broadcasting. Now, a couple of hours before the panel, we decided to go for it.&lt;/p&gt;

&lt;p&gt;This resulted in two hours of hectic coding, setup and equipment search.&lt;/p&gt;

&lt;h3 id=&quot;the-setup&quot;&gt;The Setup:&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/free-streaming/the-setup.jpg&quot; alt=&quot;The Setup&quot; /&gt;
&lt;small&gt;Photo: Tal Achituv&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/free-streaming/block-diagram.png&quot; alt=&quot;Block Diagram&quot; /&gt;
&lt;small&gt;Making this diagram took more time than building a free streaming solution&lt;small&gt;&lt;/small&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h4 id=&quot;media-server&quot;&gt;Media Server&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kurento.org/&quot;&gt;Kurento&lt;/a&gt; (LGPL-2.1) is a free media server. It implements the WebRTC spec and uses &lt;a href=&quot;https://gstreamer.freedesktop.org/&quot;&gt;GStreamer&lt;/a&gt; under the hood for any multimedia processing. In this case we used Kurento as a broadcasting server: it received one WebRTC AV stream from a presenter (the video capturing laptop) and retransmitted it via multiple WebRTC streams to viewers.&lt;/p&gt;

&lt;p&gt;We ran Kurento on a Linux VM on my laptop. The intention was to test on a VM and then deploy to some cloud service. However, due to lack of time, the debug setup became the production one.&lt;/p&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;After the Stream ended I realized that the VM had exactly 1 core and 1GB of RAM allocated to it. Handled perfectly.&lt;/li&gt;
  &lt;li&gt;If working from behind a NAT you might also need to setup a &lt;a href=&quot;https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT&quot;&gt;TURN&lt;/a&gt; and/or &lt;a href=&quot;https://en.wikipedia.org/wiki/STUN&quot;&gt;STUN&lt;/a&gt; servers. Fortunately, the Media Lab’s wired network allocates a public IP to any wired device so the VM used a bridged network and we didn’t have to worry about that.&lt;/li&gt;
  &lt;li&gt;I later found out that there are some &lt;a href=&quot;https://github.com/Kurento/kurento-docker&quot;&gt;kurento dockerfiles&lt;/a&gt; out there for quick containerized deployment of Kurento.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;signaling-server&quot;&gt;Signaling Server&lt;/h4&gt;

&lt;p&gt;The signaling server is responsible for serving static assets and connecting the clients with the Media server via WebSockets. Our Node.js server was based on Kurento’s &lt;a href=&quot;http://www.kurento.org/docs/6.1.1/tutorials/node/tutorial-3-one2many.html&quot;&gt;one-to-many video call tutorial&lt;/a&gt; and ran on my laptop.
When I say &lt;em&gt;based&lt;/em&gt; I mean completely &lt;em&gt;copied&lt;/em&gt;. The only change we made was to separate the presenter page from the viewing page and completely remove everything besides the video container on the viewer page. &lt;a href=&quot;https://github.com/tomerweller/ml-open-stream&quot;&gt;here’s the code.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/free-streaming/view-screenshot.jpg&quot; alt=&quot;Viewer&quot; /&gt;
&lt;img src=&quot;/assets/free-streaming/view-screenshot2.jpg&quot; alt=&quot;Viewer&quot; /&gt;
&lt;small&gt;Screenshots of the live viewing page. Notice the change in the favicon.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The fun thing about serving files directly from your computer is that you can hot swap them. We were tweaking the viewing experience during the stream, including changing the favicon and various css fixes.&lt;/li&gt;
  &lt;li&gt;To avoid exposing my personal laptop (signaling was running directly on my computer, not on a VM) we used the &lt;a href=&quot;https://github.com/inconshreveable/ngrok&quot;&gt;ngrok&lt;/a&gt; tunneling service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/free-streaming/terminal.png&quot; alt=&quot;Terminal&quot; /&gt;
&lt;small&gt;left: ngrok with 5 open connection. right: printout from the signaling server.&lt;/small&gt;&lt;/p&gt;

&lt;h4 id=&quot;video-capturing&quot;&gt;Video Capturing&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/achituv&quot;&gt;Tal&lt;/a&gt; managed to find a cheap video capture card in the lab (something &lt;a href=&quot;http://usefullinkage.blogspot.com/2007/09/video-capture-card-sale-penny-vidful.html&quot;&gt;like this&lt;/a&gt;) and a laptop that would actually work with it (ours didn’t). We used Firefox to connect to our presenter endpoint which handled the WebRTC handshake with the Media server.&lt;/p&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Halfway through the stream I realized that there was no audio feed connected to the capture card and that we’re actually using the laptop’s microphone. Surprisingly, the sound was fairly good.&lt;/li&gt;
  &lt;li&gt;Of course, it’s far from being a secure solution - anyone could connect to that endpoint and serve as a presenter.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;results&quot;&gt;Results&lt;/h3&gt;
&lt;p&gt;We had a peak of 37 concurrent streams and averaged around 12. Due to time constraints and because the panel was actually quite interesting we didn’t have any continuous monitoring or collected information about load but it sure felt like we could handle a lot more. The machine was responsive (even the VM) throughout the session and I’m still amazed that a tiny VM with no optimizations handled it. KUDOS to &lt;a href=&quot;http://www.kurento.org/&quot;&gt;Kurento&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;some-take-aways&quot;&gt;Some take aways&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;When you wait until the last possible minute to do something, it will take exactly one minute.&lt;/strong&gt; (&lt;a href=&quot;https://en.wikipedia.org/wiki/Parkinson%27s_law&quot;&gt;Parkinson’s Law&lt;/a&gt;). If we had decided to do this a week before then it would have taken a week. Of course, the client would be more polished and performance would be tested. But who cares? Sometimes good enough is good enough.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;There’s a tool for that.&lt;/strong&gt; I always thought that setting up live streaming is a lengthy, non-trivial task. We live in an amazing time where the tools are just there and the only thing that limits us is our perspective.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;You are a server.&lt;/strong&gt; In the early days of the internet it was clear that all nodes in the network are created equal. Anyone can consume services and anyone can provide services, whether it’s a Web page or an IRC node. The differentiation between a server and a client is a networking protocol technicality. There is no reason why a node can’t serve both as a client and a server. However, with massive data centers, Cloud computing and NAT, we’ve adopted a model of complete separation, our personal machines are clients and those behind some abstract cloud are servers. Serving anything from your machine, not just for debugging purposes, is part of the spirit of the internet. We should build tools that allow it (thanks &lt;a href=&quot;https://github.com/inconshreveable/ngrok&quot;&gt;ngrok&lt;/a&gt;!) and services that take advantage of it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thank you &lt;a href=&quot;https://twitter.com/achituv&quot;&gt;Tal Achituv&lt;/a&gt; for reminding me all of the above.&lt;/p&gt;

</description>
        <pubDate>Tue, 22 Mar 2016 04:59:59 +0000</pubDate>
        <link>https://tomerweller.com/blob/free-live-streaming-in-two-hours</link>
        <guid isPermaLink="true">https://tomerweller.com/blob/free-live-streaming-in-two-hours</guid>
        
        
      </item>
     
      <item>
        <title>Intercepting Cookies in a Chrome extension</title>
        <description>&lt;p&gt;Last week I built a Chrome extension that was supposed to solve privacy on the Web. It didn’t - but that’s a different post.&lt;/p&gt;

&lt;p&gt;I did, however, find my self in need of intercepting all cookie read/writes in a Chrome extension. This proved to be interesting and non-trivial so here’s a brain dump of the process - hopefully this helps someone somewhere. (and by someone, I’m looking at you, future self!)&lt;/p&gt;

&lt;h3 id=&quot;intercepting-cookies&quot;&gt;Intercepting cookies?&lt;/h3&gt;
&lt;p&gt;Yup. Some potential use cases:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Managing multiple Cookie stores&lt;/li&gt;
  &lt;li&gt;Using alternative Cookie stores&lt;/li&gt;
  &lt;li&gt;Namespacing Cookies&lt;/li&gt;
  &lt;li&gt;Exposing Cookies on a conditional basis like time, url, etc.&lt;/li&gt;
  &lt;li&gt;Cookie Art&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generally speaking, an extension will intercept cookies either to save your privacy or to completely violate it. &lt;em&gt;With great power comes great responsibility&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;isnt-there-already-a-cookie-api-for-chrome-extensions&quot;&gt;Isn’t there already a Cookie API for Chrome extensions?&lt;/h3&gt;
&lt;p&gt;True. And it’s a &lt;a href=&quot;https://developer.chrome.com/extensions/cookies&quot;&gt;fine API&lt;/a&gt;, yet, it does not allow real-time interception. Meaning, you can read and write cookies and even get notified when cookies change, but not manipulate them &lt;em&gt;WHILE&lt;/em&gt; they are being read / written.&lt;/p&gt;

&lt;h3 id=&quot;oogi&quot;&gt;OOGI&lt;/h3&gt;
&lt;p&gt;For the sake of this post I will build &lt;strong&gt;OOGI&lt;/strong&gt; (&lt;em&gt;shorthand for Oogifletset - the Hebrew translation of “The Cookie Monster”&lt;/em&gt;) a simple extension that statically namespaces all cookies with the prefix &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oogi$&lt;/code&gt;&lt;/strong&gt;. When cookies are set they will be prefixed before being written into the cookie store, and when being queried the prefix will be removed - making it completely transparent to remote servers.&lt;/p&gt;

&lt;p&gt;The following assumes you have basic knowledge in building a chrome extension and understand what &lt;a href=&quot;https://en.wikipedia.org/wiki/HTTP_cookie&quot;&gt;a cookie is&lt;/a&gt;. The full source code is available &lt;a href=&quot;http://www.github.com/tomerweller/oogi&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are two ways to get and set cookies. I’ll tackle each one of them separately:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;HTTP Headers&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;document.cookie&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;http-headers&quot;&gt;HTTP Headers&lt;/h3&gt;

&lt;p&gt;The HTTP Request “Cookie” header will contain all cookies currently set and the HTTP Response’s “Set-Cookie” header writes/modifies cookies.&lt;/p&gt;

&lt;p&gt;A Request’s “Cookie” header is a concatenation of all cookie names and values for the current domain and path:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;Cookie:my_int_cookie=16091; my_double_cookie=0.2545873837079853&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A Response can contain multiple “Set-Cookie” headers, one per cookie. These also contain a Path and optionally a timeout:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;Set-Cookie:my_int_cookie=5540; Path=/
Set-Cookie:my_double_cookie=0.5358087662607431; Path=/&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Luckily, Chrome extensions have a &lt;a href=&quot;https://developer.chrome.com/extensions/webRequest&quot;&gt;Webrequest API&lt;/a&gt; for manipulating HTTP requests and responses in a blocking manner.&lt;/p&gt;

&lt;p&gt;Declaring stuff in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;manifest.json&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;permissions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;webRequest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;webRequestBlocking&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*://*/*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;background&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;background.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;persistent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;a href=&quot;https://developer.chrome.com/extensions/webRequest&quot;&gt;WebRequest API&lt;/a&gt; allows us to intercept different stages in the lifecycle of an HTTP Request/Response loop.&lt;/p&gt;

&lt;p&gt;Here, in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;background.js&lt;/code&gt;, we plug into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;onBeforeSendHeaders&lt;/code&gt; to modify sent cookies and to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;onHeadersReceived&lt;/code&gt; to modify the setting of cookies:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;webRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onBeforeSendHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;requestHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;requestHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;requestHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;cookie&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;requestHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;processCookieStr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;requestHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;requestHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;requestHeaders&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;*://*/*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;blocking&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;requestHeaders&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;webRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onHeadersReceived&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;responseHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;responseHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;responseHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;set-cookie&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;responseHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;processSetCookieStr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;responseHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;responseHeaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;responseHeaders&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;*://*/*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;blocking&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;responseHeaders&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;em&gt;The actual cookie string manipulation happens in a separate file. See &lt;a href=&quot;http://www.github.com/tomerweller/oogi&quot;&gt;full code&lt;/a&gt; for specifics.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;documentcookie&quot;&gt;document.cookie&lt;/h3&gt;

&lt;p&gt;This is the fun part.&lt;/p&gt;

&lt;p&gt;Cookies can be directly manipulated with Javascript via the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie&quot;&gt;document.cookie&lt;/a&gt; property which is a javascript &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty&quot;&gt;accessor property&lt;/a&gt;. If you’ve never encountered accessor properties (like me until a week ago), you’re in for some surprises.&lt;/p&gt;

&lt;p&gt;Let’s examine &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.cookie&lt;/code&gt; in the Chrome dev tools console:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cookie&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;my_int_cookie=25760; my_double_cookie=0.563346192939207&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Looks like a String property. right? Let’s try to write a different value.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cookie&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;A=1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;A=1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cookie&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;my_int_cookie=25760; my_double_cookie=0.563346192939207; A=1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So writing to this property actually appends the written value?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cookie&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;A=2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;A=2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cookie&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;my_int_cookie=25760; my_double_cookie=0.563346192939207; A=2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Nope. It seems that the String is only a representation of an actual collection behind the scenes.&lt;/p&gt;

&lt;p&gt;So what’s going on here? Accessor properties can be set with custom getter and setter functions. That means that by invoking the property we’re actually calling a getter function and by assigning value, a setter function. These are defined using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty&quot;&gt;Object.defineProperty()&lt;/a&gt; method.&lt;/p&gt;

&lt;p&gt;Let’s try to use Object.defineProperty() function to override document.cookie:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;cookie&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;My amazing getter&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    
      &lt;span class=&quot;na&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;My amazing setter&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cookie&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;My amazing getter&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cookie&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;My&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;amazing&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setter&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Great success! This might suffice if our extension completely ignores Chrome’s internal cookie store. But, if access to the cookie store is still required, which is case for Oogi, we need to save a reference to the original getter and setter functions of document.cookie.&lt;/p&gt;

&lt;p&gt;Theoretically, the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor&quot;&gt;Object.getOwnPropertyDescriptor()&lt;/a&gt; function should help with that.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getOwnPropertyDescriptor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;cookie&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It seems, however, that Chrome doesn’t want you to access that specific descriptor.&lt;/p&gt;

&lt;p&gt;However, We can still use the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/__lookupGetter__&quot;&gt;__lookupGetter__()&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/__lookupGetter__&quot;&gt;__lookupSetter__()&lt;/a&gt; functions which are &lt;strong&gt;deprecated-do-not-use-or-the-universe-will-implode&lt;/strong&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cookieGetter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__lookupGetter__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;cookie&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cookieSetter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__lookupSetter__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;cookie&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cookieGetter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;my_int_cookie=14356; my_double_cookie=0.22253736178390682&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cookieSetter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;A=1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cookieGetter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;my_int_cookie=14356; my_double_cookie=0.22253736178390682; A=1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Bingo!&lt;/p&gt;

&lt;p&gt;However, all of this this experimentation was done in the Chrome dev tools console. How do we port this to our extension?&lt;/p&gt;

&lt;p&gt;Running custom javascript code in every webpage is done using &lt;a href=&quot;https://developer.chrome.com/extensions/content_scripts&quot;&gt;content scripts&lt;/a&gt;. However, the document object in a content script is actually a replica. Modifying it is not visible to the rest of the Javascript code in the page. Luckily, this is a &lt;a href=&quot;http://stackoverflow.com/questions/9515704/building-a-chrome-extension-inject-code-in-a-page-using-a-content-script&quot;&gt;well discussed&lt;/a&gt; issue and the most simple solution is to create a custom script element and inject it into every page.&lt;/p&gt;

&lt;p&gt;Declaring our content script in  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;manifest.json&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;permissions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;contentSettings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*://*/*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;content_scripts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;matches&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*://*/*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;content.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;run_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;document_start&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;web_accessible_resources&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;inject.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Creating a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;content.js&lt;/code&gt; script that injects an external js file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;headElement&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;documentElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;injectJs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fileName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fileName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;headElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;insertBefore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;headElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;firstElementChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;injectJs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;inject.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And finally, overriding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.cookie&lt;/code&gt; with our injected javascript:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cookieGetter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__lookupGetter__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;cookie&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cookieSetter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__lookupSetter__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;cookie&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;cookie&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;storedCookieStr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cookieGetter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;processCookieStr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storedCookieStr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;

    &lt;span class=&quot;na&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cookieString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newValue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;processSetCookieStr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cookieString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cookieSetter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;newValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s it!&lt;/p&gt;

&lt;p&gt;I left out some of the glue code to keep this post relatively short. You can checkout the complete example &lt;a href=&quot;http://www.github.com/tomerweller/oogi&quot;&gt;here&lt;/a&gt;. Feel free to submit issues and pull requests if I missed anything.&lt;/p&gt;

&lt;h5 id=&quot;huge-thanks-to-thariq-for-helping-out-with-the-js-hacking&quot;&gt;&lt;em&gt;Huge thanks to &lt;a href=&quot;https://twitter.com/trq__&quot;&gt;Thariq&lt;/a&gt; for helping out with the JS hacking!&lt;/em&gt;&lt;/h5&gt;

</description>
        <pubDate>Sun, 28 Feb 2016 04:59:59 +0000</pubDate>
        <link>https://tomerweller.com/blob/cookie-interception-chrome-extension</link>
        <guid isPermaLink="true">https://tomerweller.com/blob/cookie-interception-chrome-extension</guid>
        
        
      </item>
     
      <item>
        <title>A Blog named Blob</title>
        <description>&lt;p&gt;&lt;strong&gt;Blog?&lt;/strong&gt; A couple of weeks ago, following the &lt;a href=&quot;http://blog.parse.com/announcements/moving-on/&quot;&gt;death of Parse.com&lt;/a&gt;, I wrote a &lt;a href=&quot;/blob/parse-is-dying-all-hail-the-benevolent-dictator&quot;&gt;rant&lt;/a&gt; about the virtues of portability and how they are too often overlooked. Posting that rant on a system that inherently does not allow portability (facebook, medium, etc.) felt a bit wrong. So, following a New Year’s resolution to better document my work, a blog seemed in order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Blob?&lt;/strong&gt; Developer blogs usually have a wise ass name. This Blob is no different. Some rationalizations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;“an indeterminate mass or shape” : I’m not committing to a specific theme. Tech rant will probably rule but an occasional hummus recipe or fabrication tutorial might appear.&lt;/li&gt;
  &lt;li&gt;“&lt;strong&gt;b&lt;/strong&gt;inary &lt;strong&gt;l&lt;/strong&gt;arge &lt;strong&gt;ob&lt;/strong&gt;jects” : Same as above but in geek terminology. Anything can be represented as a binary object.&lt;/li&gt;
  &lt;li&gt;Yes. Blob sounds like Blog.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;&lt;/strong&gt; is a bullet proof, dead simple and open source static site generator. In comes markdown - out comes a static website. The output, being simple html, can be hosted virtually anywhere. As a bonus, &lt;a href=&quot;https://pages.github.com/&quot;&gt;github pages&lt;/a&gt; will build and host your jekyll website free of charge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comments&lt;/strong&gt; are a bitch. They add dynamic content to an otherwise beautifully static website. The de-facto industry standard is disqus but using that means someone else owns your discussion. It also means user session data is shared and no anonymous comments are allowed. In comes &lt;strong&gt;&lt;a href=&quot;https://github.com/posativ/isso&quot;&gt;isso&lt;/a&gt;&lt;/strong&gt; - an opensource, self hosted alternative to disqus. I love the idea of having sqlite as a datastore and, let’s face it, the ammout of expected comments (~1 per year) does not justify a multi-connection database solution. I’m running isso on a VM in an undisclosed location in the world…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design&lt;/strong&gt; - I’m slowly developing a hatred for beautiful web pages. Everything on the web is just too God damn pretty these days. I decided to get rid of all of Jekyll’s styling and start from scratch. I like fixed width fonts and I’m taking cues from &lt;a href=&quot;http://fvsch.com/&quot;&gt;Florent Verschelde’s&lt;/a&gt; &lt;a href=&quot;https://monospace-theme.tumblr.com/&quot;&gt;monospace theme&lt;/a&gt; on tumblr and &lt;a href=&quot;http://fvsch.com/code/remarkdown/&quot;&gt;remarkdow&lt;/a&gt; css library.
 &lt;a href=&quot;https://github.com/tomerweller/tomerweller.github.io/blob/master/css/custom.css&quot;&gt;My css&lt;/a&gt; file is currently 10 lines long but will probably grow when richer content is added. I’m also using a &lt;a href=&quot;https://gist.github.com/edwardhotchkiss/2005058&quot;&gt;solarized bright&lt;/a&gt; css for code highlighting and isso’s default css with minor modifications. &lt;em&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: &lt;a href=&quot;http://www.travisrich.com/&quot;&gt;Travis&lt;/a&gt; pointed out &lt;a href=&quot;http://www.motherfuckingwebsite.com&quot;&gt;motherfuckingwebsite.com&lt;/a&gt; which is spot on&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The code is available &lt;a href=&quot;https://github.com/tomerweller/tomerweller.github.io&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>Thu, 11 Feb 2016 04:59:59 +0000</pubDate>
        <link>https://tomerweller.com/blob/a-blog-named-blob</link>
        <guid isPermaLink="true">https://tomerweller.com/blob/a-blog-named-blob</guid>
        
        
      </item>
     
      <item>
        <title>Parse is dying - all hail the benevolent dictator</title>
        <description>&lt;p&gt;Facebook are &lt;a href=&quot;http://blog.parse.com/announcements/moving-on/&quot;&gt;closing down Parse&lt;/a&gt; and it seems that the developer community is thrilled. After all, they’re letting it die slowly and open-sourcing a parse compatible server. And what if they hadn’t been so nice? Have we gotten to a point where our applications depend on the generosity of 3rd party service providers? Yes. We use gmaps for mapping, Facebook for authentication, Amazon S3 for storage and much more. Some choices are almost unavoidable and some are worth the risk and/or saved resources. However, depending on 3rd party services has become the norm rather than a conscious decision.&lt;/p&gt;

&lt;p&gt;Sometimes services get shut down, sometimes pricing changes and sometimes it just doesn’t work as well as it used to / you expected. Dealing with your own bugs and errors is no fun. Dealing with someone else’s is horrific. What can we do? design for portability.&lt;/p&gt;

&lt;p&gt;Portability is a major design consideration that is often overlooked. When faced with a technology decision we should give credit to options that allow portability. For example, a hosted mongodb solution (compose, mongolab) allows you to seamlessly move your data between services or to a private mongo installation. Whereas proprietary data stores like the Google App Engine datastore or Amazon’s DynamoDB have you locked in for life or until you manually (and painfully) migrate away.&lt;/p&gt;

&lt;p&gt;Sometimes it’s worth it. Some services, such as Amazon’s S3, are so ridiculously good and the portable alternatives are so bad that other decisions just don’t make sense. But it’s still important that we understand the price we’re paying.&lt;/p&gt;

&lt;p&gt;On the flip side, and with all due credit, by creating the new open source &lt;a href=&quot;https://github.com/ParsePlatform/parse-server&quot;&gt;parse-server&lt;/a&gt;, Facebook have just turned Parse into a pretty portable piece of technology. I believe we will soon see multiple Parse-as-a-Service providers that will standardize the young Backend-as-a-Service  industry and make it a better option for those of us who still insist of thinking about portability.&lt;/p&gt;

</description>
        <pubDate>Thu, 28 Jan 2016 05:00:00 +0000</pubDate>
        <link>https://tomerweller.com/blob/parse-is-dying-all-hail-the-benevolent-dictator</link>
        <guid isPermaLink="true">https://tomerweller.com/blob/parse-is-dying-all-hail-the-benevolent-dictator</guid>
        
        
      </item>
    
  </channel>
</rss>
