<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Humanoids beLog</title>
	<atom:link href="https://humanoids.be/log/feed/" rel="self" type="application/rss+xml" />
	<link>https://humanoids.be/log/</link>
	<description></description>
	<lastBuildDate>Thu, 04 Feb 2021 22:31:49 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://humanoids.be/log/wp-content/uploads/2012/04/be1-150x150.png</url>
	<title>Humanoids beLog</title>
	<link>https://humanoids.be/log/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">34675076</site>	<item>
		<title>Sunsetting Stream Notifier</title>
		<link>https://humanoids.be/log/2021/02/sunsetting-stream-notifier/</link>
					<comments>https://humanoids.be/log/2021/02/sunsetting-stream-notifier/#comments</comments>
		
		<dc:creator><![CDATA[Martin Giger]]></dc:creator>
		<pubDate>Wed, 03 Feb 2021 16:43:23 +0000</pubDate>
				<category><![CDATA[Extensions]]></category>
		<guid isPermaLink="false">https://humanoids.be/log/?p=3284</guid>

					<description><![CDATA[<img width="700" height="505" src="https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox-700x505.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" fetchpriority="high" srcset="https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox-700x505.png 700w, https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox-416x300.png 416w, https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox-768x554.png 768w, https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox.png 990w" sizes="(max-width: 700px) 100vw, 700px" data-attachment-id="3289" data-permalink="https://humanoids.be/log/2021/02/sunsetting-stream-notifier/screenshot_2021-02-03-live-stream-notifier-for-firefox/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox.png" data-orig-size="990,714" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Screenshot_2021-02-03 Live Stream Notifier for Firefox" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox-416x300.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox-700x505.png" /><p>I have decided to halt any plans to maintain the extension and focus on other spare time open source projects instead. I should have probably made this decision about seven months ago, when Twitch integration broke, however this extension means a lot to me. It was my first browser extension that still exists and went &#8230; </p>
<p class="link-more"><a href="https://humanoids.be/log/2021/02/sunsetting-stream-notifier/" class="more-link">Continue reading<span class="screen-reader-text"> "Sunsetting Stream Notifier"</span></a></p>
<p>The post <a href="https://humanoids.be/log/2021/02/sunsetting-stream-notifier/">Sunsetting Stream Notifier</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="505" src="https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox-700x505.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" srcset="https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox-700x505.png 700w, https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox-416x300.png 416w, https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox-768x554.png 768w, https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox.png 990w" sizes="(max-width: 700px) 100vw, 700px" data-attachment-id="3289" data-permalink="https://humanoids.be/log/2021/02/sunsetting-stream-notifier/screenshot_2021-02-03-live-stream-notifier-for-firefox/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox.png" data-orig-size="990,714" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Screenshot_2021-02-03 Live Stream Notifier for Firefox" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox-416x300.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2021/02/Screenshot_2021-02-03-Live-Stream-Notifier-for-Firefox-700x505.png" />
<p>I have decided to halt any plans to maintain the extension and focus on other spare time open source projects instead. I should have probably made this decision about seven months ago, when Twitch integration broke, however this extension means a lot to me. It was my first browser extension that still exists and went through a lot of transformations. All said and done, however, I don&#8217;t really have a personal need for it anymore and don&#8217;t like some of the changes I&#8217;d have to make to it to keep it working.</p>



<p>I&#8217;ve archived the GitHub repository and pushed out one last version that informs any remaining users of the demise of the extension (and possibly bringing you here). I will delist the extension a couple days after that update, once I&#8217;m satisfied it will have reached most people it could reach. The reason I&#8217;ve made the extension non-functional is so I can retire the API credentials used by the extension.</p>



<p>The website stays available at <a href="https://freaktechnik.github.io/justintv-stream-notifications">https://freaktechnik.github.io/justintv-stream-notifications</a> but the streamnotifier.ch domain should no longer be considered safe or related to the extension.</p>



<p>I&#8217;ve pushed the &#8220;latest&#8221; in progress code to the <a href="https://github.com/freaktechnik/justintv-stream-notifications/tree/next">next</a> branch on GitHub. The plans for it were three major changes:</p>



<ul class="wp-block-list"><li>Make actions and notifications modular. This means letting the user customize the actions available on channels and the primary action, as well as letting the user set up custom rules and patterns for notifications. This would remove a lot of rather <a href="https://github.com/freaktechnik/justintv-stream-notifications/blob/next/src/background/notifier.js#L142-L173">brittle</a> code.</li><li>Build a new on-boarding experience that guides you through adding your first channel and optionally user</li><li>Begrudgingly add a way to OAuth as a user of a provider. This would have to be mandatory for Twitch and would also improve reliability of YouTube</li></ul>



<p>It is this last one that is a big reason for why I no longer feel enthusiastic about working on the extension. I would have to force users to bind their account identity to the requests the extension makes.</p>



<p>Apart from Twitch requiring authentication of a user for API requests, YouTube has also been a pain to work with. Not only is their API barely ready for live stream applications and the public rate limit is hit about half of the day, they also conduct approximately yearly audits of their API applications, which in principle is fine. They make sure applications using the YouTube API comply with their API terms. However, all of those audits have ended up with just a rapid fire of anything that looked like it could be a violation, leaving it to me to show them again and again how I am not violating their terms of use for the API. For the few correct violations that came out I&#8217;d usually get a deadline of a couple of months at best. This has lead to me half-heartedly building fixes that kind of made the extension compliant, with cleanup left for later.</p>



<p>I didn&#8217;t really want to invest a lot of time into them, because I was spending most of the time for the extension on planning out the actions/notifications rework. There were also a bunch of small maintenance tasks that kept piling up, like disabling the Smashcast and Mixer providers or updating dependencies. Further, as the extension got less important to me, I spent less and less time on it.</p>



<p>I&#8217;ve now decided that instead of every now and then spending some time on this extension I&#8217;d rather use my spare time to build extensions that empower users and make the internet better for small services and decentralized solutions. As such, my <a href="https://addons.mozilla.org/addon/coupon-booklet/?utm_source=humanoids.be&amp;utm_content=latest%20extension">latest extension</a> (which is also already a couple of years old) is a coupon manager that doesn&#8217;t rely on any service to collect the coupons.</p>



<p>Thank you for using Stream Notifier throughout the years, giving constructive feedback and recommending it to your friends.  I explicitly don&#8217;t want to make any replacement recommendations, so if you feel like you need a browser extension that notifies you of streams, use the <a href="https://addons.mozilla.org">addons.mozilla.org</a> search and discover possible candidates.</p>
<p>The post <a href="https://humanoids.be/log/2021/02/sunsetting-stream-notifier/">Sunsetting Stream Notifier</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://humanoids.be/log/2021/02/sunsetting-stream-notifier/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3284</post-id>	</item>
		<item>
		<title>Sustainable smart home with the TXT</title>
		<link>https://humanoids.be/log/2019/03/sustainable-smart-home-with-the-txt/</link>
		
		<dc:creator><![CDATA[Martin Giger]]></dc:creator>
		<pubDate>Sun, 31 Mar 2019 17:28:22 +0000</pubDate>
				<category><![CDATA[Hardware]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Robotik]]></category>
		<category><![CDATA[fischertechnik]]></category>
		<category><![CDATA[iot]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[txt]]></category>
		<guid isPermaLink="false">https://humanoids.be/log/?p=3259</guid>

					<description><![CDATA[<img width="700" height="525" src="https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-700x525.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" srcset="https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-700x525.jpg 700w, https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-400x300.jpg 400w, https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-768x576.jpg 768w, https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-1440x1080.jpg 1440w, https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-2880x2160.jpg 2880w" sizes="(max-width: 700px) 100vw, 700px" data-attachment-id="3260" data-permalink="https://humanoids.be/log/2019/03/sustainable-smart-home-with-the-txt/img_20190116_112733/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733.jpg" data-orig-size="4032,3024" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="IMG_20190116_112733" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-400x300.jpg" data-large-file="https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-700x525.jpg" /><p>fischertechnik launched the smart home kit last year. A very good move on a conceptual level. Smart home and IoT (internet of things) are rapidly growing technology sectors. The unique placement of the TXT allows it to be a perfect introductory platform to this world. However, the smart home platform from fischertechnik relies on a &#8230; </p>
<p class="link-more"><a href="https://humanoids.be/log/2019/03/sustainable-smart-home-with-the-txt/" class="more-link">Continue reading<span class="screen-reader-text"> "Sustainable smart home with the TXT"</span></a></p>
<p>The post <a href="https://humanoids.be/log/2019/03/sustainable-smart-home-with-the-txt/">Sustainable smart home with the TXT</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="525" src="https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-700x525.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-700x525.jpg 700w, https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-400x300.jpg 400w, https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-768x576.jpg 768w, https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-1440x1080.jpg 1440w, https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-2880x2160.jpg 2880w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3260" data-permalink="https://humanoids.be/log/2019/03/sustainable-smart-home-with-the-txt/img_20190116_112733/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733.jpg" data-orig-size="4032,3024" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="IMG_20190116_112733" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-400x300.jpg" data-large-file="https://humanoids.be/log/wp-content/uploads/2019/03/IMG_20190116_112733-700x525.jpg" />
<p>fischertechnik launched the <a href="https://www.fischertechnik.de/en/products/playing/robotics/544624-robotics-txt-smart-home">smart home kit</a> last year. A very good move on a conceptual level. Smart home and IoT (internet of things) are rapidly growing technology sectors. The unique placement of the TXT allows it to be a perfect introductory platform to this world.</p>



<p>However, the smart home platform from fischertechnik relies on a central cloud server. This leads to vendor lock-in and challenges to integrate it with other products. Making the cloud your primary interface also means you&#8217;re vulnerable to internet outages. Of course the risk really depends on the device type, but you wouldn&#8217;t want your thermostat to stop working, just because your internet was down.</p>



<span id="more-3259"></span>



<p><a href="https://fischertechnik.de">fischertechnik</a> is a toy company, though their toy is intended to also serve as a prototyping platform for automation solutions and as education tool. As part of that they, similar to the much better known solution from Lego, have an interface that can run programs to control actors and read out sensors. The latest iteration of this interface is called the fischertechnik TXT. It has an ARM Cortex A8 and can easily be used with custom firmware. This makes it a great platform to build sustainable IoT applications.</p>



<p>Sadly, fischertechnik&#8217;s kit doesn&#8217;t promote decentralized smart home solutions, instead it opts to provide a proprietary cloud platform:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Beyond that, the TXT Controller can be connected to a cloud server, in which the sensors’ data is saved, and can be retrieved from anywhere in the world. So using a user interface, a so-called “dashboard”, the various sensor data can be permanently monitored, and the movement of the camera can be controlled.</p><cite>Description of the ROBOTICS TXT Smart Home kit</cite></blockquote>



<p>Mozilla started <a href="https://iot.mozilla.org/">venturing into IoT recently</a>. They are trying to advocate for better privacy and user freedom by promoting interoperability. These goals are unified in a proposal for a device API that is based on web protocols called <a href="https://mozilla-iot.github.io/wot/">&#8220;Web of Things&#8221;</a>. It is developed in collaboration with smart home and &#8220;industry 4.0&#8221; manufacturers. This API isn&#8217;t necessarily implemented by each device directly, some devices are too low powered to provide a web server or are using other successful local mesh networks like Z-Wave or Zigbee. In these cases a gateway that is connected to the user&#8217;s local network would provide the web thing API.</p>



<p>The web thing API breaks physical devices down into three attributes: properties, actions and events. Properties as stateful values that can both be changed by the device and the user (I&#8217;ll often refer to the user as the client). A device can however declare a property as read-only or add input value restrictions. Actions let the user execute an action on the device that either isn&#8217;t stateful or affects multiple properties. Lastly, events are fired by the device to indicate a momentary effect that is not reflected in the state. Above that is a <a href="https://mozilla-iot.github.io/schemas/">capabilities</a> system, with which devices can indicate the semantics of their features. For example a light bulb can advertise itself as being a &#8220;Lamp&#8221;, it&#8217;s brightness property will be a &#8220;BrightnessProperty&#8221; and the power toggle will be an &#8220;OnOffProperty&#8221;. These allow clients to expose appropriate UIs and behaviors for devices. The protocol is available over HTTP(S) and optionally WebSockets for real-time communication of changes.</p>



<p>Mozilla is developing both a reference gateway to control devices using this protocol and reference implementations in multiple languages to build web things with. The &#8220;WebThing gateway&#8221; also has an adapter system to bridge other smart home protocols to the web of things data model.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="700" height="570" data-attachment-id="3262" data-permalink="https://humanoids.be/log/2019/03/sustainable-smart-home-with-the-txt/txt_webthing_gateway/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2019/03/txt_webthing_gateway-e1553177233770.png" data-orig-size="1161,945" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="txt_webthing_gateway" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2019/03/txt_webthing_gateway-e1553177233770-369x300.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2019/03/txt_webthing_gateway-e1553177233770-700x570.png" src="https://humanoids.be/log/wp-content/uploads/2019/03/txt_webthing_gateway-e1553177233770-700x570.png" alt="" class="wp-image-3262" srcset="https://humanoids.be/log/wp-content/uploads/2019/03/txt_webthing_gateway-e1553177233770-700x570.png 700w, https://humanoids.be/log/wp-content/uploads/2019/03/txt_webthing_gateway-e1553177233770-369x300.png 369w, https://humanoids.be/log/wp-content/uploads/2019/03/txt_webthing_gateway-e1553177233770-768x625.png 768w, https://humanoids.be/log/wp-content/uploads/2019/03/txt_webthing_gateway-e1553177233770.png 1161w" sizes="auto, (max-width: 700px) 100vw, 700px" /><figcaption>WebThing gateway UI representing the TXT</figcaption></figure>



<p>A TXT is easily powerful enough to run the web server required for the web thing API on its own and be a proper web thing. I&#8217;ve taken the python APIs from the <a href="https://cfw.ftcommunity.de/ftcommunity-TXT/">community firmware</a> and Mozilla&#8217;s python web thing library to create an app that can turn the TXT into a web thing. It currently exposes all inputs (I1-I8), outputs (M1-M4/O1-O8), telemetry of the TXT, the camera as well as the counter inputs (C1-C4) as properties. Only the actor properties are writable. Further it provides actions to play a built-in sound and reset a counter input.</p>



<p>The fischertechnik solution for smart home functionality uses MQTT. Why not just adapt that to the web of things? MQTT is only a protocol and the actual packets aren&#8217;t standardized. Sadly fischertechnik&#8217;s solution is designed to communicate with a cloud solution from a third party. Thus, you&#8217;d would have to figure out how to make the TXT connect with a custom MQTT consumer. All in all, I decided it was much simpler and resilient to write an implementation of the web thing protocol that runs on the TXT.</p>



<p>The &#8220;WebOfTXT&#8221; app, the application connecting the TXT to the web of things I wrote, offers configuration for the sensor and actor types connected to the TXT. After the configuration is set, the user has to start the web thing server. Before starting the server, the schema for the thing is built based on the selections from the user. A <code>QTimer</code> is started to get updated property values. As an exception, the actor properties are only changed by clients of the web thing API, setting the speeds or levels for the outputs. The two actions trigger the respective functions in the TXT API based on the provided inputs. All inputs from API clients are verified by the web thing python package to be valid inputs. For example the actor levels are checked to be integers in the allowed range for the actor type. These limits are also published as a schema in the web thing API, so clients can also expose these limits to the user.</p>



<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<span class="embed-privacy-url"><a href="https://www.youtube.com/embed/4uicH0LA2Qo?version=3&#038;rel=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;fs=1&#038;hl=en-US&#038;autohide=2&#038;wmode=transparent">Open embedded content from YouTube</a></span>
</div><figcaption>Demo showing the web UI on the WebThing gateway to interact with the TXT</figcaption></figure>



<p>A special case is the camera. It is exposed as an image snapshot. However the image is not served via the web thing API. HTTP can already handle images just fine and there&#8217;s no need for scaffolding information. Further an image can&#8217;t be written, only read. Thus the image property just points to an image file hosted by the TXT. The TXT updates this image about ten times a second. However refreshing it is entirely up to the client and no notification is sent when a new image is available. For all other properties, the web thing sends an event whenever a property value is changed, so the client can immediately display the updated value.</p>



<p>I found out, that starting the web thing server in the main app thread blocks the TXT UI. Thus the web thing server is started in a separate python thread with its own event loop. Otherwise, the application could not be stopped from the TXT, since it would no longer be registering touch screen inputs.</p>



<figure class="wp-block-pullquote"><blockquote><p>It is relatively simple to build solutions for the TXT that can be used in conjunction with other smart home or IoT devices</p></blockquote></figure>



<p>fischertechnik&#8217;s smart home solution is focused on getting the user up and running with little effort and little first party infrastructure. It is relatively simple to build solutions for the TXT that can be used in conjunction with other smart home or IoT devices, though. I believe building your own solution is even more valuable for education on the topic, for example because you can easily consume the data yourself afterward. Bringing up privacy, security and interoperability in IoT education is important, especially considering major manufacturers are avoiding the topics.</p>



<p>Source code of my python bridge can be found in the <a href="https://github.com/freaktechnik/WebOfTXT">freaktechnik/WebOfTXT</a> GitHub repository. The python script is only about 750 lines of code, however it requires a couple of python packages to do the heavy lifting. Those are installed by the <code>build.sh</code> script, which produces a ZIP file that can be uploaded to the TXT via the web UI of the community firmware. This should be a good starting point to create a more specific web thing with the TXT and annotate it with the proper capabilities. I want to thank all Mozilla employees and friends from the fischertechnik community that have helped me during the creating of this app, as it was my first time seriously writing python.</p>



<p><em>A slightly shortened, fischertechnik-specific variant of this article was published in the <a href="https://ftpedia.de">ft:pedia</a> <a href="https://ftcommunity.de/ftpedia_ausgaben/ftpedia-2019-1.pdf">1/2019</a> (pages 64-67)</em></p>
<p>The post <a href="https://humanoids.be/log/2019/03/sustainable-smart-home-with-the-txt/">Sustainable smart home with the TXT</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3259</post-id>	</item>
		<item>
		<title>Getting Help in Text Chat</title>
		<link>https://humanoids.be/log/2018/08/getting-help-in-text-chat/</link>
		
		<dc:creator><![CDATA[Martin Giger]]></dc:creator>
		<pubDate>Mon, 20 Aug 2018 15:32:25 +0000</pubDate>
				<category><![CDATA[Alltag]]></category>
		<category><![CDATA[chat]]></category>
		<category><![CDATA[develop]]></category>
		<category><![CDATA[documentation]]></category>
		<category><![CDATA[help]]></category>
		<category><![CDATA[muc]]></category>
		<category><![CDATA[question]]></category>
		<guid isPermaLink="false">https://humanoids.be/log/?p=3181</guid>

					<description><![CDATA[<img width="700" height="328" src="https://humanoids.be/log/wp-content/uploads/2018/08/help-head-700x328.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="Dimly lit man sitting on couch with laptop on knees" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2018/08/help-head-700x328.jpg 700w, https://humanoids.be/log/wp-content/uploads/2018/08/help-head-474x222.jpg 474w, https://humanoids.be/log/wp-content/uploads/2018/08/help-head-768x359.jpg 768w, https://humanoids.be/log/wp-content/uploads/2018/08/help-head-1440x674.jpg 1440w, https://humanoids.be/log/wp-content/uploads/2018/08/help-head-2880x1348.jpg 2880w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3227" data-permalink="https://humanoids.be/log/2018/08/getting-help-in-text-chat/help-head/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2018/08/help-head.jpg" data-orig-size="4000,1872" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="help-head" data-image-description="" data-image-caption="&lt;p&gt;Photo by Andrew Neel on Unsplash&lt;/p&gt;
" data-medium-file="https://humanoids.be/log/wp-content/uploads/2018/08/help-head-474x222.jpg" data-large-file="https://humanoids.be/log/wp-content/uploads/2018/08/help-head-700x328.jpg" /><p>Developers like to help other developers. Many times via text chats like IRC, Slack, Gitter or Discord. This article is mainly aimed at developers asking for help. However it can also be applied to other situations, even if the concepts don&#8217;t fully apply. Now for the short overview for the very impatient, though especially those &#8230; </p>
<p class="link-more"><a href="https://humanoids.be/log/2018/08/getting-help-in-text-chat/" class="more-link">Continue reading<span class="screen-reader-text"> "Getting Help in Text Chat"</span></a></p>
<p>The post <a href="https://humanoids.be/log/2018/08/getting-help-in-text-chat/">Getting Help in Text Chat</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="328" src="https://humanoids.be/log/wp-content/uploads/2018/08/help-head-700x328.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="Dimly lit man sitting on couch with laptop on knees" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2018/08/help-head-700x328.jpg 700w, https://humanoids.be/log/wp-content/uploads/2018/08/help-head-474x222.jpg 474w, https://humanoids.be/log/wp-content/uploads/2018/08/help-head-768x359.jpg 768w, https://humanoids.be/log/wp-content/uploads/2018/08/help-head-1440x674.jpg 1440w, https://humanoids.be/log/wp-content/uploads/2018/08/help-head-2880x1348.jpg 2880w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3227" data-permalink="https://humanoids.be/log/2018/08/getting-help-in-text-chat/help-head/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2018/08/help-head.jpg" data-orig-size="4000,1872" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="help-head" data-image-description="" data-image-caption="&lt;p&gt;Photo by Andrew Neel on Unsplash&lt;/p&gt;
" data-medium-file="https://humanoids.be/log/wp-content/uploads/2018/08/help-head-474x222.jpg" data-large-file="https://humanoids.be/log/wp-content/uploads/2018/08/help-head-700x328.jpg" />
<p>Developers like to help other developers. Many times via text chats like IRC, Slack, Gitter or Discord.</p>



<p>This article is mainly aimed at developers asking for help. However it can also be applied to other situations, even if the concepts don&#8217;t fully apply.</p>



<p>Now for the short overview for the very impatient, though especially those should take the second to last point to heart and read the full article:</p>



<ul class="wp-block-list"><li>Directly state your question</li><li>Don&#8217;t ask for 1:1s</li><li>Answer inquiries in full detail</li><li>Read linked resources thoroughly</li><li>Reference documentation and examples when asking<br /></li></ul>



<span id="more-3181"></span>



<p>Before I get into the details, I want to mention that I have been helping all kinds of developers via text chat for a couple of years on multiple different platforms. Some days I&#8217;m a bit more patient, other days I&#8217;ll just give up. Don&#8217;t be angry at people when they don&#8217;t want to help you anymore, they&#8217;re doing this (most likely) for free!</p>



<h2 class="wp-block-heading">Directly state your question</h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>The solution is not to ask to ask, but just to ask. Someone who is idling on the channel and only every now and then glances what&#8217;s going on is unlikely to answer to your &#8220;asking to ask&#8221; question, but your actual problem description may pique their interest and get them to answer.</p><cite><a href="https://sol.gfxile.net/dontask.html">Jari Komppa</a></cite></blockquote>



<p>You may often be tempted to ask if anyone&#8217;s available or understands your framework. Don&#8217;t (<a href="https://sol.gfxile.net/dontask.html">ask</a>), people will help if they can. If you ask to ask first, they may not even get involved, because there&#8217;s no problem there that their brain wants to solve.</p>



<p>When stating your problem, try to refrain from explanations like &#8220;it doesn&#8217;t work&#8221;. It not working is obvious to the helper, otherwise you wouldn&#8217;t have to seek help. Describe what you&#8217;re trying to do and what&#8217;s actually happening, just like you&#8217;re reporting a bug. Especially when dealing with programming, it often helps to include an excerpt of what you&#8217;re currently doing that&#8217;s not working. Stack overflow has a <a href="https://stackoverflow.com/help/mcve">good guide</a> explaining how to craft an answerable coding inquiry. Then there&#8217;s <a href="https://github.com/shlomif/how-to-share-code-online">this guide</a> to help you with sharing code.<br /></p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="5049" height="4000" data-attachment-id="3228" data-permalink="https://humanoids.be/log/2018/08/getting-help-in-text-chat/edwin-andrade-153753-unsplash/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2018/08/edwin-andrade-153753-unsplash.jpg" data-orig-size="5049,4000" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="edwin-andrade-153753-unsplash" data-image-description="" data-image-caption="&lt;p&gt;Photo by Edwin Andrade on Unsplash&lt;/p&gt;
" data-medium-file="https://humanoids.be/log/wp-content/uploads/2018/08/edwin-andrade-153753-unsplash-379x300.jpg" data-large-file="https://humanoids.be/log/wp-content/uploads/2018/08/edwin-andrade-153753-unsplash-700x555.jpg" src="https://humanoids.be/log/wp-content/uploads/2018/08/edwin-andrade-153753-unsplash.jpg" alt="Crowd, standing, with hands in the air" class="wp-image-3228" srcset="https://humanoids.be/log/wp-content/uploads/2018/08/edwin-andrade-153753-unsplash.jpg 5049w, https://humanoids.be/log/wp-content/uploads/2018/08/edwin-andrade-153753-unsplash-379x300.jpg 379w, https://humanoids.be/log/wp-content/uploads/2018/08/edwin-andrade-153753-unsplash-768x608.jpg 768w, https://humanoids.be/log/wp-content/uploads/2018/08/edwin-andrade-153753-unsplash-700x555.jpg 700w, https://humanoids.be/log/wp-content/uploads/2018/08/edwin-andrade-153753-unsplash-1440x1141.jpg 1440w, https://humanoids.be/log/wp-content/uploads/2018/08/edwin-andrade-153753-unsplash-2880x2282.jpg 2880w" sizes="auto, (max-width: 5049px) 100vw, 5049px" /><figcaption>Photo by Edwin Andrade on Unsplash</figcaption></figure>



<h2 class="wp-block-heading">Don&#8217;t ask for 1:1s</h2>



<p>When asking for help in a multi-user chat room, you should also expect to troubleshoot your issue in that chat room.</p>



<p>If you&#8217;re insisting on getting help in a 1:1, I can recommend looking on Twitter; some people love to help you in their DMs.</p>



<p>You don&#8217;t want to share your code with a public chat room for confidentiality reasons? You probably shouldn&#8217;t share it with one random stranger from the internet either. Just saying.<br /></p>



<h2 class="wp-block-heading">Answer inquiries in full detail</h2>



<p>You will get asked follow-up questions, because you probably left out something or there are specific conditions for a bug. Answer these questions in the fullest detail possible. Pay close attention to the wording, experienced helpers will ask well formulated questions.</p>



<h2 class="wp-block-heading">Read linked resources thoroughly</h2>



<p>Before going on and assuming, completely read linked documentation, guides and so forth. Don&#8217;t just skim the contents, read thoroughly and try to understand. Just like questions you&#8217;d get asked, documentation uses very precise language to describe things.</p>



<p>It&#8217;s fine if you don&#8217;t understand the documentation. You can ask specific questions about it so that you can learn to eventually read the documentation yourself without having to ask for help. That&#8217;s the end goal, after all. You don&#8217;t want to end up always having to ask other people to solve a problem. Try to develop new skills when asking questions; especially understanding documentation is a very valuable skill.</p>



<h2 class="wp-block-heading">Reference documentation and examples correctly</h2>



<p>When asking for clarification on details you don&#8217;t understand, try to reference to examples or documentation, that way helpers don&#8217;t have to try and figure out what exactly you&#8217;re talking about.</p>



<p>To the helper it will often be ambiguous what you are talking about without that, since they potentially know much more about the language or library. That&#8217;s why they can help you after all. Sometimes they&#8217;re just your rubber duck to bounce things off of and spot the missing semicolon (P.S.: please use static code checking like linters).<br /></p>



<h2 class="wp-block-heading">Tell people when their suggestions are too complex<br /></h2>



<p>Developers are usually very excited about new things. New syntax, new libraries, new patterns, they&#8217;ll suggest all of them to you. While it&#8217;s nice to learn about them, try to understand your problem in the technologies you know first before exploring new grounds as an alternative solution. Sometimes it will not be possible to solve your issue with things that you are familiar with.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="2400" height="1800" data-attachment-id="3229" data-permalink="https://humanoids.be/log/2018/08/getting-help-in-text-chat/loud-hailer-character-shows-shouting-yelling-and-bullying/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2018/08/photo_84305_20170213.jpg" data-orig-size="2400,1800" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;Stuart Miles&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;Loud Hailer Character Showing Shouting Yelling And Bullying&quot;,&quot;created_timestamp&quot;:&quot;1379846557&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;Loud Hailer Character Shows Shouting Yelling And Bullying&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Loud Hailer Character Shows Shouting Yelling" data-image-description="" data-image-caption="&lt;p&gt;Loud Hailer Character Showing Shouting Yelling&lt;/p&gt;
" data-medium-file="https://humanoids.be/log/wp-content/uploads/2018/08/photo_84305_20170213-400x300.jpg" data-large-file="https://humanoids.be/log/wp-content/uploads/2018/08/photo_84305_20170213-700x525.jpg" src="https://humanoids.be/log/wp-content/uploads/2018/08/photo_84305_20170213.jpg" alt="" class="wp-image-3229" srcset="https://humanoids.be/log/wp-content/uploads/2018/08/photo_84305_20170213.jpg 2400w, https://humanoids.be/log/wp-content/uploads/2018/08/photo_84305_20170213-400x300.jpg 400w, https://humanoids.be/log/wp-content/uploads/2018/08/photo_84305_20170213-768x576.jpg 768w, https://humanoids.be/log/wp-content/uploads/2018/08/photo_84305_20170213-700x525.jpg 700w, https://humanoids.be/log/wp-content/uploads/2018/08/photo_84305_20170213-1440x1080.jpg 1440w" sizes="auto, (max-width: 2400px) 100vw, 2400px" /></figure>



<p>Usually this kind of &#8220;technology creep&#8221; is easy to spot when descriptors like &#8220;nicely&#8221; or &#8220;elegantly&#8221; are used to describe a solution. Or when they ask you about the specific environment you&#8217;re in. Just to be clear, these aren&#8217;t absolute indicators, and you shouldn&#8217;t be afraid to learn a little bit of new technology. After all, you want to learn and improve and not just stay stuck with the things you already know.</p>



<p>In short, tell people when they&#8217;re pushing too many new things on you that you can&#8217;t follow. Usually there&#8217;s a simpler solution than to use three new syntax features and two new libraries.</p>



<hr class="wp-block-separator"/>



<p>Lastly, please keep this article in mind. Not only to make the lives of helpers easier. One day you will hopefully be helping others, and linking them to such a resource is surely very helpful! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br /></p>
<p>The post <a href="https://humanoids.be/log/2018/08/getting-help-in-text-chat/">Getting Help in Text Chat</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3181</post-id>	</item>
		<item>
		<title>Showcase all your Twitch emotes</title>
		<link>https://humanoids.be/log/2018/08/showcase-all-your-twitch-emotes/</link>
		
		<dc:creator><![CDATA[Martin Giger]]></dc:creator>
		<pubDate>Wed, 15 Aug 2018 09:37:03 +0000</pubDate>
				<category><![CDATA[Webservice]]></category>
		<category><![CDATA[emotes]]></category>
		<category><![CDATA[kappa]]></category>
		<category><![CDATA[Twitch]]></category>
		<guid isPermaLink="false">https://humanoids.be/log/?p=3214</guid>

					<description><![CDATA[<img width="700" height="415" src="https://humanoids.be/log/wp-content/uploads/2018/08/bloghead-700x415.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2018/08/bloghead-700x415.png 700w, https://humanoids.be/log/wp-content/uploads/2018/08/bloghead-474x281.png 474w, https://humanoids.be/log/wp-content/uploads/2018/08/bloghead-768x455.png 768w, https://humanoids.be/log/wp-content/uploads/2018/08/bloghead.png 1080w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3223" data-permalink="https://humanoids.be/log/2018/08/showcase-all-your-twitch-emotes/bloghead/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2018/08/bloghead.png" data-orig-size="1080,640" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="bloghead" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2018/08/bloghead-474x281.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2018/08/bloghead-700x415.png" /><p>Emotes are a very important feature of Twitch chat culture. Because of this, there aren&#8217;t just emotes you get from subscribing to broadcasters, but also extensions like BetterTTV and FrankerFaceZ that add more emotes to be used in Twitch chat. Many broadcasters have an image in their panels showing the emotes that are available for &#8230; </p>
<p class="link-more"><a href="https://humanoids.be/log/2018/08/showcase-all-your-twitch-emotes/" class="more-link">Continue reading<span class="screen-reader-text"> "Showcase all your Twitch emotes"</span></a></p>
<p>The post <a href="https://humanoids.be/log/2018/08/showcase-all-your-twitch-emotes/">Showcase all your Twitch emotes</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="415" src="https://humanoids.be/log/wp-content/uploads/2018/08/bloghead-700x415.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2018/08/bloghead-700x415.png 700w, https://humanoids.be/log/wp-content/uploads/2018/08/bloghead-474x281.png 474w, https://humanoids.be/log/wp-content/uploads/2018/08/bloghead-768x455.png 768w, https://humanoids.be/log/wp-content/uploads/2018/08/bloghead.png 1080w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3223" data-permalink="https://humanoids.be/log/2018/08/showcase-all-your-twitch-emotes/bloghead/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2018/08/bloghead.png" data-orig-size="1080,640" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="bloghead" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2018/08/bloghead-474x281.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2018/08/bloghead-700x415.png" />
<p>Emotes are a very important feature of Twitch chat culture. Because of this, there aren&#8217;t just emotes you get from subscribing to broadcasters, but also extensions like BetterTTV and FrankerFaceZ that add more emotes to be used in Twitch chat.</p>



<p>Many broadcasters have an image in their panels showing the emotes that are available for their channel. Usually an outdated image, especially since subscriber emotes can be updated much more frequently.</p>



<p>Twitch Extensions are dynamic panels that can update themselves. So sure enough, I decided to solve this by making the<a href="https://www.twitch.tv/ext/3yumzvi6r4wfycsk7vt1kbtto9s0n3"> Twitch extension &#8220;Emotes Showcase&#8221;</a> that just displays the channel&#8217;s emotes, that simple.<br /></p>



<span id="more-3214"></span>



<h2 class="wp-block-heading">What does it do?</h2>



<p>Of course displaying emotes isn&#8217;t very simple. Because Twitch emotes are a very big ecosystem. Not only does the panel display subscriber reward emotes if your channel has any, but it also shows any BetterTTV or FrankerFaceZ emotes that are enabled for your channel.</p>



<p>The focus is on your sub emotes when they exist, the BTTV and FFZ sections are collapsed in that case. Viewers can still expand the sections to discover the additional emotes they can use with BTTV and FFZ.</p>



<p>The data used to display emotes is based on the subscription emote sets that <a href="https://twitchemotes.com">twitchemotes.com</a> provide in their API. The emote sets are updated every 24 hours. If you&#8217;ve just gotten your first emotes it may take a couple hours for the extension to display them. BTTV and FFZ are directly based on their API.<br /></p>



<h2 class="wp-block-heading">Why make it now?</h2>



<p>I had the idea for this extension since quite some time. And amazingly no one had created it before. A Twitch Extension developer jam, created by <a href="https://twitch.tv/luckynos7evin">LuckyNoS7evin</a>, finally gave me a reason to build it. And someone else also created a similar extension for that jam.<br /></p>



<p>It having such a simple feature set made it perfect for an extension jam with limited time.<br /></p>



<h2 class="wp-block-heading">Will it ever change?</h2>



<p>There are a lot of things I want to add to the extension. Currently it is completely configuration free. Once Twitch lets me store configuration on their systems I&#8217;ll add various configurations options to define what to show and how. I&#8217;m also planning to add a force refresh button that lets you refresh all currently displayed panels so viewers get the latest sub emotes when a new one available.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="768" data-attachment-id="3234" data-permalink="https://humanoids.be/log/2018/08/showcase-all-your-twitch-emotes/cover-2/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2018/08/cover.png" data-orig-size="1024,768" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="cover" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2018/08/cover-400x300.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2018/08/cover-700x525.png" src="https://humanoids.be/log/wp-content/uploads/2018/08/cover.png" alt="" class="wp-image-3234" srcset="https://humanoids.be/log/wp-content/uploads/2018/08/cover.png 1024w, https://humanoids.be/log/wp-content/uploads/2018/08/cover-400x300.png 400w, https://humanoids.be/log/wp-content/uploads/2018/08/cover-768x576.png 768w, https://humanoids.be/log/wp-content/uploads/2018/08/cover-700x525.png 700w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">I want to use this now, tell me how!</h2>



<p>You can get the Emote Showcase extension from <a href="https://www.twitch.tv/ext/3yumzvi6r4wfycsk7vt1kbtto9s0n3">your Twitch dashboard</a>. Don&#8217;t forget to add it to an extension panel after installing it! As with most of my projects, the source code is available on <a href="https://github.com/freaktechnik/twitch-emotes-extension">GitHub</a>.</p>
<p>The post <a href="https://humanoids.be/log/2018/08/showcase-all-your-twitch-emotes/">Showcase all your Twitch emotes</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3214</post-id>	</item>
		<item>
		<title>Definitive Bot Land Beta tier list</title>
		<link>https://humanoids.be/log/2018/06/definitive-bot-land-beta-tier-list/</link>
		
		<dc:creator><![CDATA[Martin Giger]]></dc:creator>
		<pubDate>Sun, 10 Jun 2018 09:00:53 +0000</pubDate>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[bot land]]></category>
		<category><![CDATA[livestream]]></category>
		<category><![CDATA[Stream]]></category>
		<category><![CDATA[streaming]]></category>
		<guid isPermaLink="false">https://humanoids.be/log/?p=3198</guid>

					<description><![CDATA[<img width="700" height="356" src="https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-700x356.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-700x356.png 700w, https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-474x241.png 474w, https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-768x390.png 768w, https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-1440x732.png 1440w, https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land.png 1920w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3201" data-permalink="https://humanoids.be/log/2018/06/definitive-bot-land-beta-tier-list/screenshot_2018-06-10-bot-land/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land.png" data-orig-size="1920,976" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Screenshot_2018-06-10 Bot Land" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-474x241.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-700x356.png" /><p>Bot Land is a browser-based game that is still in development. You can learn more at https://bot.land. I streamed creating this tier list. You can watch the VOD of it on YouTube: https://youtu.be/F-PUJEErrQA Attack/Offense Vanilla Lasers Pros Blind fire Cons Countered by reflect Not a good secondary weapon Attacking Any defense that doesn&#8217;t reflect they&#8217;re &#8230; </p>
<p class="link-more"><a href="https://humanoids.be/log/2018/06/definitive-bot-land-beta-tier-list/" class="more-link">Continue reading<span class="screen-reader-text"> "Definitive Bot Land Beta tier list"</span></a></p>
<p>The post <a href="https://humanoids.be/log/2018/06/definitive-bot-land-beta-tier-list/">Definitive Bot Land Beta tier list</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="356" src="https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-700x356.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-700x356.png 700w, https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-474x241.png 474w, https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-768x390.png 768w, https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-1440x732.png 1440w, https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land.png 1920w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3201" data-permalink="https://humanoids.be/log/2018/06/definitive-bot-land-beta-tier-list/screenshot_2018-06-10-bot-land/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land.png" data-orig-size="1920,976" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Screenshot_2018-06-10 Bot Land" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-474x241.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2018/06/Screenshot_2018-06-10-Bot-Land-700x356.png" /><p><em>Bot Land is a browser-based game that is still in development. You can learn more at <a href="https://bot.land">https://bot.land</a>. I streamed creating this tier list. You can watch the VOD of it on YouTube: <a href="https://youtu.be/F-PUJEErrQA">https://youtu.be/F-PUJEErrQA</a><br />
</em></p>
<h2>Attack/Offense</h2>
<h3>Vanilla Lasers</h3>
<p><em>Pros</em></p>
<ul>
<li>Blind fire</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Countered by reflect</li>
<li>Not a good secondary weapon</li>
</ul>
<h4>Attacking</h4>
<p>Any defense that doesn&#8217;t reflect they&#8217;re great against.</p>
<h4>Defending</h4>
<p>Fine, very easily countered though.</p>
<h3>Missiles</h3>
<p><em>Pros</em></p>
<ul>
<li>Fire in every direction</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Countered by reflect</li>
<li>Don&#8217;t do enough damage</li>
</ul>
<h4>Attacking</h4>
<p>Ok, not great. Vulnerable to weapons with a bigger range, and vulnerable to weapons with a smaller range.</p>
<h4>Defending</h4>
<p>Good at being a secondary weapon on Artillery bots, for example.</p>
<h3>Artillery</h3>
<p><em>Pros</em></p>
<ul>
<li>Biggest range</li>
<li>Lots of damage</li>
<li>They splash damage adjacent tiles</li>
<li>They don&#8217;t care about reflect</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Travel time</li>
<li>Countered by teleport, melee</li>
</ul>
<h4>Attacking</h4>
<p>Great against defenses that don&#8217;t move much.</p>
<h4>Defending</h4>
<p>Ok choice for defense, but not great against many attack patterns. You will need some other bots that &#8220;pin&#8221; the attackers, so you can hit them with artillery. Usually a secondary weapon vastly increases the effectiveness of artillery bots. I&#8217;d recommend zappers or missiles as secondary weapon.</p>
<h3>Zapper</h3>
<p><em>Pros</em></p>
<ul>
<li>Works while you&#8217;re using another weapon</li>
<li>Hits cloaked targets (since it&#8217;s untargeted)</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Has to be used at short range</li>
</ul>
<h4>Attacking</h4>
<p>Must have for melee bots, since it&#8217;s free extra damage.</p>
<h4>Defending</h4>
<p>Ok if you like the attacker to be close to you (which you shouldn&#8217;t like), and thus not too great because they take a slot that you could use for support hardware.</p>
<h3>Melee</h3>
<p><em>Pros</em></p>
<ul>
<li>Deals good damage</li>
<li>Good counter to most ranged damage if you can get close</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Bot has to get close to enemies</li>
<li>Weak against artillery/other ranged damage</li>
<li>Countered by bigger range (artillery etc)</li>
</ul>
<h4>Attacking</h4>
<p>Great against most defenses. Works well with zappers, doesn&#8217;t need any other weapons. Gets even better if you move faster (teleport, thrusters)</p>
<h4>Defending</h4>
<p>Again, ok if you like the attacker to be close to you (see zappers, which are better at that)</p>
<h3>Landmines</h3>
<p><em>Pros</em></p>
<ul>
<li>Explode enemies, I guess&#8230;</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Enemies have to step on them</li>
<li>Needs good scripts</li>
</ul>
<h4>Attacking</h4>
<p>Very, very niche. But can be ok.</p>
<h4>Defending</h4>
<p>Weak, really hard to use effectively.</p>
<h3>Inferno Lasers</h3>
<p><em>Pros</em></p>
<ul>
<li>They burn things</li>
<li>Easier to use than normal lasers</li>
<li>Keep dealing damage to cloaked enemies/de-cloak enemies</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>They don&#8217;t deal as much hit damage</li>
<li>Countered by reflect</li>
</ul>
<h4>Attacking</h4>
<p>Have edge cases where they are better than normal lasers, in general they are about the same though. Maybe a bit easier to use.</p>
<h4>Defending</h4>
<p>Similar to lasers. Not really better or worse.</p>
<h3>Inferno Zappers</h3>
<p><em>Pros</em></p>
<ul>
<li>They still zap</li>
<li>Do fire damage (de-cloak, enemy can move out of range)</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Deal less initial damage</li>
<li>DoT on zapper is less valuable</li>
<li>Reflect</li>
</ul>
<h4>Attacking</h4>
<p>Ok. Great with melee attack bots</p>
<h4>Defending</h4>
<p>Like normal zappers, not that great. But better against some attack strategies as a close quarters weapon, since you keep dealing damage to enemies that retreat from directly attacking you.</p>
<h3>Stunning Lasers</h3>
<p><em>Pros</em></p>
<ul>
<li><strong>Unique</strong> effect of stunning.</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Requires a strategy tailored to them, due to reduced damage</li>
<li>Countered by reflect</li>
</ul>
<h4>Attacking</h4>
<p>Hard to use for attacks, require other damage sources to work.</p>
<h4>Defending</h4>
<p>Good for ranged defenses (which is really the only good kind of defense), even when they just hit random targets.</p>
<h3>Vampiric Lasers</h3>
<p><em>Pros</em></p>
<ul>
<li>Heals your bot (without taking up an extra slot or turn)</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Deals less damage per hit</li>
<li>Countered by reflect</li>
</ul>
<h4>Attacking</h4>
<p>Less wasted turns when attacking chips. Ok, drop-in replacement of lasers that can be better in edge cases.</p>
<h4>Defending</h4>
<p>Better healing sources for defense than sacrificing laser damage.</p>
<h3>Acceleration Missiles</h3>
<p><em>Note: haven&#8217;t used the new, revised acceleration missiles</em></p>
<p><em>Pros</em></p>
<ul>
<li>Can eventually deal a lot of damage.</li>
<li>Sound really neat on paper</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Not great in practice</li>
<li>Countered by reflect</li>
</ul>
<p>I don&#8217;t think you should be using them. Neither for attack nor defense.</p>
<h2>Support/Defense</h2>
<h3>Cloaking</h3>
<p><em>Pros</em></p>
<ul>
<li>Enemies can&#8217;t see you when you&#8217;re cloaked (while you don&#8217;t walk into them)</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Doesn&#8217;t work well with melee or Zappers</li>
<li>Cooldown &#8211; can only cloak every now and then</li>
</ul>
<h4>Attacking</h4>
<p>Ok for attacks, requires very specific usage, don&#8217;t use with melee!</p>
<h4>Defending</h4>
<p>Not as valuable, so very niche.</p>
<h3>Regen</h3>
<p><em>Pros</em></p>
<ul>
<li>Restores life</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Only restores a little life</li>
</ul>
<h4>Attacking</h4>
<p>Don&#8217;t bother, if you&#8217;d survive due to regen, another form of support may have been more effective.</p>
<h4>Defending</h4>
<p>Don&#8217;t bother either, use the chip.</p>
<h3>Teleport</h3>
<p><em>Pros</em></p>
<ul>
<li>It moves your bot far quickly.</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Has a cooldown</li>
</ul>
<h4>Attacking</h4>
<p>Great for retreating, not as good for quick melee or similar.</p>
<h4>Defending</h4>
<p>Great for getting in the first hit, retreating is less of an issue/consideration.</p>
<h3>Thrusters</h3>
<p><em>Pros</em></p>
<ul>
<li>Makes you attack faster</li>
<li>Can potentially kill enemy just before it would kill you (1v1 duel winner)</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Not as good if your enemy has more thrusters (or haste)</li>
<li>Not as useful if you have teleport</li>
</ul>
<h4>Attacking</h4>
<p>Good if you have spare slots</p>
<h4>Defending</h4>
<p>Good if there&#8217;s a thruster meta, but really only use it for spare slots, haste chip has similar effect for free.</p>
<h3>Reflect</h3>
<p><em>Pros</em></p>
<ul>
<li>Reflects ALL the things</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Sometimes on cooldown</li>
<li>Never a guaranteed reflect</li>
</ul>
<h4>Attacking</h4>
<p>Use whenever you encounter things that you can reflect. Prefer over any other defensive hardware. I have two versions of many bots, one with and one without reflect, since reflect is useless when attacking any defense without lasers or missiles. What to replace reflect with depends on the strategy for the bot.</p>
<h4>Defending</h4>
<p>Reflecting wall in front is pretty good, if your bots die quick, all bots should probably have some reflect. If you use reflect, you&#8217;ll see more artillery and melee attacks.<br />
Makes it really easy to deal with any strat that uses weapons that can be reflected and you can focus on other strategies.</p>
<h3>Shield</h3>
<p><em>Pros</em></p>
<ul>
<li>Shields your bot from damage</li>
<li>Shield other entities</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Have to be activated</li>
</ul>
<h4>Attacking</h4>
<p>Solid, better than repair for simple strats.</p>
<h4>Defending</h4>
<p>Depends, can be strong, but active healing by specialized healers is stronger, since those don&#8217;t take up a slot or turn.</p>
<h3>Armor</h3>
<p><em>Pros</em></p>
<ul>
<li>Reduces damage taken</li>
<li>Passive</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Reflect is the better slot filler</li>
<li>Worse than regen, only absorbs so much damage, while regen can regenerate infinite damage taken (<em>in theory</em>)</li>
</ul>
<h4>Attacking</h4>
<p>Not sure why you&#8217;re not using reflect&#8230;</p>
<h4>Defending</h4>
<p>At least have the decency to use regen.</p>
<h3>EMP</h3>
<p><em>Pros</em></p>
<ul>
<li>Disables weapons</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Not great against activatables</li>
<li>Hard to time right, due to range</li>
</ul>
<h4>Attacking</h4>
<p>If you&#8217;re using EMP as an attacker, I&#8217;m sure you have a good reason for it.</p>
<h4>Defending</h4>
<p>Good to shut down that one annoying thing you forgot to deal with in your defense. Requires some custom code to be effective.</p>
<h3>Repair</h3>
<p><em>Pros</em></p>
<ul>
<li>Repair yourself</li>
<li>Repair others</li>
<li>Repair CPU</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>Not an AoE</li>
</ul>
<h4>Attacking</h4>
<p>Do you want to live forever? If yes, build a bot that retreats and heals (and hope no-one follows you, as in TP away so they don&#8217;t see you anymore)</p>
<h4>Defending</h4>
<p>Use it when you don&#8217;t have area repair yet. Use it when you have some CPU cult worshiping your CPU. Have a dedicated bot, probably.</p>
<h3>Area Repair</h3>
<p><em>Pros</em></p>
<ul>
<li>Heals things</li>
<li>AoE</li>
</ul>
<p><em>Cons</em></p>
<ul>
<li>AoE (for attacking)</li>
<li>Doesn&#8217;t heal things that aren&#8217;t bots</li>
</ul>
<h4>Attacking</h4>
<p>Bad, because AoEs when attacking are hard.</p>
<h4>Defending</h4>
<p>Great. Use it (on a dedicated bot, or just anywhere)</p>
<h2>Chips</h2>
<p>Nice-to-have, don&#8217;t rely on them, generally not game-changing.</p>
<p>The post <a href="https://humanoids.be/log/2018/06/definitive-bot-land-beta-tier-list/">Definitive Bot Land Beta tier list</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3198</post-id>	</item>
		<item>
		<title>Browser Extensions should Work Together</title>
		<link>https://humanoids.be/log/2017/11/browser-extensions-work-together/</link>
		
		<dc:creator><![CDATA[Martin Giger]]></dc:creator>
		<pubDate>Mon, 13 Nov 2017 17:25:35 +0000</pubDate>
				<category><![CDATA[Extensions]]></category>
		<category><![CDATA[add-on]]></category>
		<category><![CDATA[browser]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[webextensions]]></category>
		<guid isPermaLink="false">https://humanoids.be/log/?p=3167</guid>

					<description><![CDATA[<img width="700" height="210" src="https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations-700x210.png" class="webfeedsFeaturedVisual wp-post-image" alt="Live Stream Notifier + Notification Sound + Streamlink Helper = ❤" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations-700x210.png 700w, https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations-474x142.png 474w, https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations-768x230.png 768w, https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations.png 1000w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3173" data-permalink="https://humanoids.be/log/2017/11/browser-extensions-work-together/extension-integrations/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations.png" data-orig-size="1000,300" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Extension Integrations Header" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations-474x142.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations-700x210.png" /><p>Most browser extensions do a thing. And they do that thing in their isolated little world. Many of them do their thing pretty well. Many of them are built to do many things. Many of them are built to do just one little thing. But only few of them talk to other extensions to do &#8230; </p>
<p class="link-more"><a href="https://humanoids.be/log/2017/11/browser-extensions-work-together/" class="more-link">Continue reading<span class="screen-reader-text"> "Browser Extensions should Work Together"</span></a></p>
<p>The post <a href="https://humanoids.be/log/2017/11/browser-extensions-work-together/">Browser Extensions should Work Together</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="210" src="https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations-700x210.png" class="webfeedsFeaturedVisual wp-post-image" alt="Live Stream Notifier + Notification Sound + Streamlink Helper = ❤" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations-700x210.png 700w, https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations-474x142.png 474w, https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations-768x230.png 768w, https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations.png 1000w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3173" data-permalink="https://humanoids.be/log/2017/11/browser-extensions-work-together/extension-integrations/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations.png" data-orig-size="1000,300" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Extension Integrations Header" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations-474x142.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2017/11/extension-integrations-700x210.png" /><p>Most browser extensions do a thing. And they do that thing in their isolated little world. Many of them do their thing pretty well. Many of them are built to do many things. Many of them are built to do just one little thing. But only few of them talk to other extensions to do things.</p>
<p>And I&#8217;d like to see more extensions talk to each other to do things.<span id="more-3167"></span></p>
<h2>A Couple of Examples</h2>
<h3>Running a Task</h3>
<p>One of my extensions lets you know when creators are streaming. Some people like using external tools to watch those streams (for many reasons). While I do not want to support a native application that interacts with Firefox to launch the tool, I have instead found an extension that already provides integration with the tool and Firefox and asked nicely to add an API for other extensions to be able to launch the tool. And now I can offer an option to open streams with the tool when that extension is installed. Since this is a feature only few users would be using it is a much more efficient approach for me and it makes it simpler for users of that other extension, since they don&#8217;t have to install two native applications to interact with the tool.</p>
<p>There are many other things that other extensions may already be doing and you don&#8217;t necessarily want to repeat in your own extension. I can think of interacting with some APIs to share content on a service or applying certain modifications to a page as generic examples.</p>
<h3>An API for a Custom Feature</h3>
<p>Another one of my extensions plays a sound when a notification is shown. That sound can be customized. It&#8217;s something Firefox doesn&#8217;t do out of the box. If other extensions also want to have that sound played when they show notifications, and thus make it way simpler for users to get a unified notification experience from Firefox, they can just tell that extension that they are showing a notification.</p>
<p>I initially opted to build a separate extension to play a sound for new notifications because I did not want to add my own solution in every notifier extension I maintain. And because some operating systems already play a sound, so why should I always just have that feature built into my extension, when it&#8217;s easily modularizable and users can opt into it by installing an extension.</p>
<p>There are many other extensions, especially in the tab management category that do very custom stuff with how they handle native Firefox features. Giving other extensions a way to directly interact with those additional features opens new and exciting opportunities.</p>
<h3>Adding more Functionality</h3>
<p>The popular Twitch modification extension <a href="https://www.frankerfacez.com/">FrankerFaceZ</a> has an <a href="https://ffzap.download/">add-on pack</a> for more emotes and additional customizations. The add-on pack fully integrates into the UI of the base extension.</p>
<p>Other classic examples for this include Firebug extensions (which are now just normal developer tools extensions) and extensions adding features to ad blockers.</p>
<h2>How can Extensions Integrate with Each Other?</h2>
<p>There is a well hidden feature in the very basic messaging API for WebExtensions: you can send a message to another extension. And of course that extension can then reply to your message, or send you more messages, since it gets your extension&#8217;s ID as part of the sender info.</p>
<p>The API in question is the <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/sendMessage">sendMessage</a> API in the runtime namespace. You just specify the ID of the extension to send your message to as the first parameter. Extensions can also open ports between them to exchange more than just single messages in a context. To listen for incoming messages from other extensions a separate event listener <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/onMessageExternal">onMessageExternal</a> is required. The same goes for incoming port connections with onConnectExternal.</p>
<p>When listening you do not only get the message from the other extension, but also which extension is interacting with you. This allows you to allow extension-based filtering to reduce the threat of abuse or for users to further customize their experience.</p>
<p>The actual messaging protocol has to be defined by the individual extensions. The protocols I&#8217;ve used so far are both documented in the README of the extension.</p>
<p>Some extensions expose an API in the page they modify with a global object. This lets users customize extension behavior via user scripts or other extensions. I don&#8217;t have an example of any extension that does this and has a documented API.</p>
<p>I&#8217;ve created <a href="https://github.com/freaktechnik/awesome-extension-apis">awesome-extension-apis</a> as a curated resource for extensions that have a messaging API for other extensions to use. Please add your extensions with messaging APIs to that list!</p>
<h2>Why Should they Integrate with Each Other?</h2>
<p>Primarily to reduce configuration repetition for users. At least that&#8217;s what I think integrations are primarily useful for. Instead of every extension providing its own solution for a problem they can reduce it to a single point of configuration for the user by all requiring the same extension.</p>
<p>This is not really fitting for core features, since users have to install a second extension. But to expand the abilities of your extension I think it is fine to ask users to install a different extension. Especially for less extension related things like a notification sound. It may be a harder sell for integrations with services, like Streamlink, however I feel the problem is similar to requiring a native application. It may even be a little less severe, as installing an extension requires a lower trust level from the user and is easier.</p>
<p>The post <a href="https://humanoids.be/log/2017/11/browser-extensions-work-together/">Browser Extensions should Work Together</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3167</post-id>	</item>
		<item>
		<title>Democratizing our Twitter Account</title>
		<link>https://humanoids.be/log/2017/10/democratizing-our-twitter-account/</link>
		
		<dc:creator><![CDATA[Martin Giger]]></dc:creator>
		<pubDate>Tue, 31 Oct 2017 16:15:48 +0000</pubDate>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[board]]></category>
		<category><![CDATA[buffer]]></category>
		<category><![CDATA[content]]></category>
		<category><![CDATA[contributors]]></category>
		<category><![CDATA[deomcarcy]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[ideas]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[queue]]></category>
		<category><![CDATA[Twitter]]></category>
		<guid isPermaLink="false">https://humanoids.be/log/?p=3131</guid>

					<description><![CDATA[<img width="700" height="369" src="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-700x369.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-700x369.jpg 700w, https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-474x250.jpg 474w, https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-768x405.jpg 768w, https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-1440x760.jpg 1440w, https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-2880x1520.jpg 2880w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3159" data-permalink="https://humanoids.be/log/2017/10/democratizing-our-twitter-account/img_20171030_161605_blog/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog.jpg" data-orig-size="4032,2128" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Post-it Content Queue" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-474x250.jpg" data-large-file="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-700x369.jpg" /><p>In early 2016 the Swiss Mozilla Community met up to discuss goals and community structure. During a discussion on the state of our Twitter account @MozillaCH I pitched the idea of having a tool to manage content like replies with contributors instead of just people with direct access to the account. Finding a solution I &#8230; </p>
<p class="link-more"><a href="https://humanoids.be/log/2017/10/democratizing-our-twitter-account/" class="more-link">Continue reading<span class="screen-reader-text"> "Democratizing our Twitter Account"</span></a></p>
<p>The post <a href="https://humanoids.be/log/2017/10/democratizing-our-twitter-account/">Democratizing our Twitter Account</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="369" src="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-700x369.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-700x369.jpg 700w, https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-474x250.jpg 474w, https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-768x405.jpg 768w, https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-1440x760.jpg 1440w, https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-2880x1520.jpg 2880w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3159" data-permalink="https://humanoids.be/log/2017/10/democratizing-our-twitter-account/img_20171030_161605_blog/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog.jpg" data-orig-size="4032,2128" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="Post-it Content Queue" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-474x250.jpg" data-large-file="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161605_blog-700x369.jpg" /><p>In early 2016 the Swiss Mozilla Community met up to discuss goals and community structure. During a discussion on the state of our <a href="https://twitter.com/mozillach">Twitter account @MozillaCH</a> I <a href="https://discourse.mozilla.org/t/better-twitter-curation/10721">pitched the idea</a> of having a tool to manage content like replies with contributors instead of just people with direct access to the account.<span id="more-3131"></span></p>
<h2>Finding a solution</h2>
<p>I then took the task of investigating existing solutions. After not finding anything that really fit my vision of a system to manage tweets going through an editorial flow, I decided to build the tool myself. Hopefully with contributions from others, but given our community size I had no expectations.</p>
<p>I first wanted to automate adding Tweet drafts and then sending them with a Trello board. Just <a href="https://github.com/blog/2256-a-whole-new-github-universe-announcing-new-tools-forums-and-features">then</a> GitHub released project boards. We already use GitHub for community organization, so managing tweets wasn&#8217;t unthinkable.</p>
<p>Moving to GitHub also has the advantage of reducing the barrier of entry for potential tweet writers. All you need is a GitHub account. This expanded the vision of the tool allow contributors to suggest content for the Twitter account.</p>
<h2>How it works</h2>
<p>The basic idea is that we have a card per planned tweet on a project board. We move that card through multiple stages on that board, until it is in a column for content that should be tweeted. Other columns can be sources for tweets that automatically generate a card when new content is available, like an ICAL feed from <a href="https://reps.mozilla.org">REMO</a> or new Twitter mentions. Other columns may be for editorial management, like proof reading.</p>
<p>Every card has an issue attached to it, which has information like the tweet content, when it will be tweeted or what tweet it is a reply to. For the tool to understand the issue, it needs to follow a standardized format. To make interaction with the tool easier, it comments when content is not valid. Comments also serve as reminder for unfinished content that is scheduled to be tweeted soon.</p>
<p>Most of the content sources and management functionality is individually controllable, including if the tool should use them at all.</p>
<p>The tool is Node application that interacts with issues, project board and the twitter account. Configuration is a static JSON structure, or via the environment, since it can also be deployed via a Docker container.</p>
<h2>Starting to use it</h2>
<p>It took about a year until the tool was ready enough. And then breaking it a few times and fixing it before we finally deployed it for use with our Twitter account. And even after that we&#8217;ve found some bugs and fixed some. In short, the tool is still in its infancy.</p>
<p>We use a buffer-like system, where only one tweet is sent out every day for unscheduled content. We may need to tweet more than once a day. For the moment it seems our content gets spread out nicely thanks to this system, instead of compulsive tweets &amp; retweets in the middle of the night.</p>
<p>You can now contribute content for the @MozillaCH Twitter account in the <a href="https://github.com/mozillach/tweets">mozillach/tweets repo on GitHub</a>. We have tweet curators that will then help you create a valid tweet and move it through the content queue.</p>
<h2>The future</h2>
<p>Meanwhile a test is running for the @MozillaReps Twitter account, and hopefully others will follow.</p>
<p>My goal is to finish test coverage for the tool, to improve its reliability. Eventually I want to add a web interface to make management of settings easier. Others have suggested making it possible to post to other services like Facebook or Telegram Channels.</p>
<p>Sadly the documentation is pretty basic currently, there is a README explaining the configuration, but actual functionality is only documented in our <a href="https://raw.githubusercontent.com/mozillach/tweets/aa4342deb02a6a2ef27998b9628d518aa774211b/CONTRIBUTING.md">CONTRIBUTING.md</a> for the @MozillaCH tweet board.</p>
<p>Source code is of course available, in this case on GitHub: <a href="https://github.com/mozillach/gh-projects-content-queue/">https://github.com/mozillach/gh-projects-content-queue/</a></p>
<p>Feel free to install it for your own Twitter accounts, file issues and pull requests. I believe this is a very accessible, new way to allow collaboration on Twitter content.</p>
<p><a href="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161733_blog.jpg"><img loading="lazy" decoding="async" data-attachment-id="3157" data-permalink="https://humanoids.be/log/2017/10/democratizing-our-twitter-account/img_20171030_161733_blog/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161733_blog.jpg" data-orig-size="1776,619" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="IMG_20171030_161733_blog" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161733_blog-474x165.jpg" data-large-file="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161733_blog-700x244.jpg" class="aligncenter size-full wp-image-3157" src="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161733_blog.jpg" alt="Ideas: Comment and Share!" width="1776" height="619" srcset="https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161733_blog.jpg 1776w, https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161733_blog-474x165.jpg 474w, https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161733_blog-768x268.jpg 768w, https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161733_blog-700x244.jpg 700w, https://humanoids.be/log/wp-content/uploads/2017/10/IMG_20171030_161733_blog-1440x502.jpg 1440w" sizes="auto, (max-width: 1776px) 100vw, 1776px" /></a></p>
<p>The post <a href="https://humanoids.be/log/2017/10/democratizing-our-twitter-account/">Democratizing our Twitter Account</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3131</post-id>	</item>
		<item>
		<title>Code coverage reports for WebExtensions</title>
		<link>https://humanoids.be/log/2017/10/code-coverage-reports-for-webextensions/</link>
		
		<dc:creator><![CDATA[Martin Giger]]></dc:creator>
		<pubDate>Wed, 25 Oct 2017 12:26:37 +0000</pubDate>
				<category><![CDATA[Extensions]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[ava]]></category>
		<category><![CDATA[coverage]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[nyc]]></category>
		<category><![CDATA[test]]></category>
		<category><![CDATA[unit test]]></category>
		<category><![CDATA[unit tests]]></category>
		<category><![CDATA[webextensions]]></category>
		<guid isPermaLink="false">https://humanoids.be/log/?p=3114</guid>

					<description><![CDATA[<img width="700" height="398" src="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png 1007w, https://humanoids.be/log/wp-content/uploads/2015/11/coverage-474x270.png 474w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3069" data-permalink="https://humanoids.be/log/2015/11/checking-code-coverage-of-add-on-sdk-extensions/coverage/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png" data-orig-size="1007,573" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="coverage overview table" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2015/11/coverage-474x270.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png" /><p>It&#8217;s been quite a while since I last posted on here, and interestingly about the same topic: code coverage analysis in Firefox extensions. And since then Firefox has gotten a completely new extension system. I&#8217;ve been really busy porting my extensions and not writing blog posts. The add-on SDK conveniently came with a test runner &#8230; </p>
<p class="link-more"><a href="https://humanoids.be/log/2017/10/code-coverage-reports-for-webextensions/" class="more-link">Continue reading<span class="screen-reader-text"> "Code coverage reports for WebExtensions"</span></a></p>
<p>The post <a href="https://humanoids.be/log/2017/10/code-coverage-reports-for-webextensions/">Code coverage reports for WebExtensions</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="398" src="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png 1007w, https://humanoids.be/log/wp-content/uploads/2015/11/coverage-474x270.png 474w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3069" data-permalink="https://humanoids.be/log/2015/11/checking-code-coverage-of-add-on-sdk-extensions/coverage/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png" data-orig-size="1007,573" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="coverage overview table" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2015/11/coverage-474x270.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png" /><p>It&#8217;s been quite a while since I last posted on here, and interestingly about the same topic: code coverage analysis in Firefox extensions. And since then Firefox has gotten a completely new extension system. I&#8217;ve been really busy porting my extensions and not writing blog posts.</p>
<p>The add-on SDK conveniently came with a test runner built into the JPM command line tool. <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions" rel="noopener nofollow">WebExtensions</a> don&#8217;t, which forces the choice of test runner on the developer.</p>
<p>If you use a traditional test runner, you&#8217;re probably not really struggling with code coverage. You may have had to do a little bit of research to properly mock the environment of the test runner, so your extension code can run in it, most likely ending up with something that exports the DOM globals from <a href="https://www.npmjs.com/package/jsdom" rel="noopener nofollow">JSDOM</a> and some stub of the WebExtensions API (my choice is <a href="https://www.npmjs.com/package/sinon-chrome" rel="noopener nofollow">sinon-chrome</a>). And then you&#8217;re done.<br />
<span id="more-3114"></span></p>
<pre><pre class="brush: jscript; title: ; notranslate">
const browserEnv = require(&amp;amp;amp;amp;amp;amp;quot;browser-env&amp;amp;amp;amp;amp;amp;quot;);
const browser = require(&amp;amp;amp;amp;amp;amp;quot;sinon-chrome/webextensions&amp;amp;amp;amp;amp;amp;quot;);

browserEnv();
global.browser = browser;
</pre>
<p>Trouble is, I like the fancy modern test runners, which run tests in parallel. Of course we could use the global injection approach there. However we would sacrifice running tests in parallel inside a single test file. While we may still be able to run multiple test files at once depending on the test runner (my choice is <a href="https://www.npmjs.com/package/ava" rel="noopener nofollow">ava</a>).</p>
<p>So how can we run them in parallel then? The extension files all need a window global and a <code>browser</code>/<code>chrome</code> global. Sure, but luckily JSDOM by default doesn&#8217;t export the window global to the node global, instead it creates a sandbox. And into that sandbox we also inject the WebExtension API stubs and whatever DOM APIs we need that JSDOM doesn&#8217;t come with. Finally we execute the file to test in that sandbox (using <code>eval</code>) and pass in the window as context to the test.</p>
<pre><pre class="brush: jscript; title: ; notranslate">
const fs = require(&amp;amp;amp;amp;amp;amp;quot;mz/fs&amp;amp;amp;amp;amp;amp;quot;);
const { JSDOM } = require(&amp;amp;amp;amp;amp;amp;quot;jsdom&amp;amp;amp;amp;amp;amp;quot;);

/**
 * Creates sandbox with DOM and WebExtensions APIs and loads instrumented files in it.
 *
 * @param {&#x5B;string]} files - Paths of files to load in the DOM sandbox.
 * @param {string} &#x5B;html=&amp;amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;amp;lt;html&amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;quot;] - Document to create the DOM sandbox around.
 * @returns {object} JSDOM global the files are loaded in.
 */
const getEnv = async (files, html = &amp;amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;amp;lt;html&amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;quot;) =&amp;amp;amp;amp;amp;amp;gt; {
 const dom = new JSDOM(html, {
   runScripts: 'outside-only',
   virtualConsole
 });
 dom.window.browser = require(&amp;amp;amp;amp;amp;amp;quot;sinon-chrome/webextensions&amp;amp;amp;amp;amp;amp;quot;);
 // Purge that instance of the browser stubs, so tests have their own env.
 delete require.cache&#x5B;path.join(__dirname, '../node_modules/sinon-chrome/webextensions/index.js')];
 for(const file of files) {
   dom.window.eval(await fs.readFile(path.join(__dirname, file), 'utf8'));
 }
 return dom;
};
</pre>
<p>Sounds simple enough, and results in us getting a sandbox per test. A lot of overhead, just to run tests in parallel. We haven&#8217;t even started with overhead though.</p>
<p>Like in the <a href="https://humanoids.be/log/2015/11/checking-code-coverage-of-add-on-sdk-extensions/" rel="noopener nofollow">article for the add-on SDK</a>, to get coverage, files have to be instrumented and coverage has be read from them. This setup isn&#8217;t doing that yet. Instead it currently loads the tested files using node&#8217;s <code>fs</code> module (actually, using a promisified version) and then evaluates them inside the sandbox. At no point could my coverage tool of choice, <a href="https://www.npmjs.com/package/nyc" rel="noopener nofollow">nyc</a>, instrument them or read coverage.</p>
<p>To sum up, we have to manually instrument the files when loading them using nyc and then manually export the coverage results so nyc can generate a report. Now, the instrumenting bit is actually an API nyc offers. Trouble is the reading the coverage bit.</p>
<p>Let&#8217;s start with the simple task, instrumenting. The following code snippet replaces the <code>readFile</code> call in the <code>getEnv</code> function from before. It only instruments files using nyc when nyc is being used to run the tests, else it just reads the file.</p>
<pre><pre class="brush: jscript; title: ; notranslate">
const fs = require(&amp;amp;amp;amp;amp;amp;quot;fs/mz&amp;amp;amp;amp;amp;amp;quot;);
const cp = require(&amp;amp;amp;amp;amp;amp;quot;child_process&amp;amp;amp;amp;amp;amp;quot;);
const util = require(&amp;amp;amp;amp;amp;amp;quot;util&amp;amp;amp;amp;amp;amp;quot;);
const ef = util.promisify(cp.execFile);

/**
 * Returns the source of the specified file, instrumented when running nyc.
 *
 * @param {string} sourcePath - Path to the file that should be loaded.
 * @returns {string} Potentially instrumented source code of the given file.
 */
const instrument = async (sourcePath) =&amp;amp;amp;amp;amp;amp;gt; {
 if(!instrumentCache.has(sourcePath)) {
   if(!process.env.NYC_CONFIG) {
     const source = await fs.readFile(sourcePath, 'utf8');
     instrumentCache.set(sourcePath, source);
   }
   else {
     const instrumented = await ef(process.execPath, &#x5B;
       './node_modules/.bin/nyc',
       'instrument',
       sourcePath
     ], {
       cwd: process.cwd(),
       env: process.env
     });
     instrumentCache.set(sourcePath, instrumented.stdout.toString('utf-8'));
   }
 }
 return instrumentCache.get(sourcePath);
};
</pre>
<p>Sadly we can&#8217;t just share the coverage global with the JSDOM scopes. Instead we have to manually collect the coverage and hand it over to nyc.</p>
<p>Luckily nyc reads all &#8220;.json&#8221; files in the &#8220;.nyc_output&#8221; directory as coverage results. Thus we can just write the coverage results to a uniquely named JSON file in that directory once tests are done (oh, and we close the window to clean up all garbage):</p>
<pre><pre class="brush: jscript; title: ; notranslate">
const fs = require(&amp;amp;amp;amp;amp;amp;quot;mz/fs&amp;amp;amp;amp;amp;amp;quot;);
const mkdirp = require(&amp;amp;amp;amp;amp;amp;quot;mkdirp&amp;amp;amp;amp;amp;amp;quot;);
const util = require(&amp;amp;amp;amp;amp;amp;quot;util&amp;amp;amp;amp;amp;amp;quot;);
const mk = util.promisify(mkdirp);

/**
 * Saves coverage to disk for nyc to collect and cleans up the JSDOM sandbox.
 *
 * @param {JSDOMWindow} window - Window global of the sandbox. Window property
 *                               on the global getEnv returns.
 * @returns {undefined}
 */
const cleanUp = async (window) =&amp;amp;amp;amp;amp;amp;gt; {
 if(process.env.NYC_CONFIG) {
   const nycConfig = JSON.parse(process.env.NYC_CONFIG);
   await mk(nycConfig.tempDirectory);
   await fs.writeFile(path.join(nycConfig.tempDirectory, `${Date.now()}_${process.pid}_${++id}.json`), JSON.stringify(window.__coverage__), 'utf8');
 }
 window.close();
};
</pre>
<p><strong>Update (2018-11-10):</strong> in nyc 13.1.0 tempDirectory was changed to tempDir.</p>
<p>Code in this article are excerpts from the test suites I use for two of my extensions. <a href="https://github.com/freaktechnik/advanced-github-notifier" rel="noopener nofollow">Advanced GitHub Notifier</a> has the fancy one we built throughout this article, which essentially creates a sandbox per test and <a href="https://github.com/freaktechnik/justintv-stream-notifications" rel="noopener nofollow">Live Stream Notifier</a> uses a global scope-polluting setup. Both setups have their drawbacks. Polluting the global environment means that tests depending on the state of the API stubs or similar have to run in series. However it is much faster than initializing a whole DOM sandbox for every test and requires a lot more setup.</p>
<p>The post <a href="https://humanoids.be/log/2017/10/code-coverage-reports-for-webextensions/">Code coverage reports for WebExtensions</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3114</post-id>	</item>
		<item>
		<title>Checking Code Coverage of Add-on SDK Extensions</title>
		<link>https://humanoids.be/log/2015/11/checking-code-coverage-of-add-on-sdk-extensions/</link>
		
		<dc:creator><![CDATA[Martin Giger]]></dc:creator>
		<pubDate>Wed, 04 Nov 2015 22:18:08 +0000</pubDate>
				<category><![CDATA[Add-on SDK]]></category>
		<category><![CDATA[coverage]]></category>
		<category><![CDATA[instrument]]></category>
		<category><![CDATA[istanbul]]></category>
		<category><![CDATA[jetpack]]></category>
		<category><![CDATA[jpm]]></category>
		<category><![CDATA[test]]></category>
		<category><![CDATA[unit]]></category>
		<category><![CDATA[unit test]]></category>
		<category><![CDATA[xpi]]></category>
		<guid isPermaLink="false">http://humanoids.be/log/?p=3057</guid>

					<description><![CDATA[<img width="700" height="398" src="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png 1007w, https://humanoids.be/log/wp-content/uploads/2015/11/coverage-474x270.png 474w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3069" data-permalink="https://humanoids.be/log/2015/11/checking-code-coverage-of-add-on-sdk-extensions/coverage/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png" data-orig-size="1007,573" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="coverage overview table" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2015/11/coverage-474x270.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png" /><p>Code coverage statistics are very useful. They tell you how much of your code never gets executed during the unit tests. So you always know what to write unit tests for, because 100% coverage doesn&#8217;t exist. And sometimes you can&#8217;t cover all code. That&#8217;s why normally you are happy, if the coverage is above a &#8230; </p>
<p class="link-more"><a href="https://humanoids.be/log/2015/11/checking-code-coverage-of-add-on-sdk-extensions/" class="more-link">Continue reading<span class="screen-reader-text"> "Checking Code Coverage of Add-on SDK Extensions"</span></a></p>
<p>The post <a href="https://humanoids.be/log/2015/11/checking-code-coverage-of-add-on-sdk-extensions/">Checking Code Coverage of Add-on SDK Extensions</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="398" src="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png 1007w, https://humanoids.be/log/wp-content/uploads/2015/11/coverage-474x270.png 474w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3069" data-permalink="https://humanoids.be/log/2015/11/checking-code-coverage-of-add-on-sdk-extensions/coverage/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png" data-orig-size="1007,573" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="coverage overview table" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2015/11/coverage-474x270.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2015/11/coverage.png" /><p>Code coverage statistics are very useful. They tell you how much of your code never gets executed during the unit tests. So you always know what to write unit tests for, because 100% coverage doesn&#8217;t exist. And sometimes you can&#8217;t cover all code. That&#8217;s why normally you are happy, if the coverage is above a certain thresh hold, but having a higher coverage is always ok</p>
<p>One of the typical coverage tools for CommonJS based code is <em><a href="https://www.npmjs.com/package/istanbul">istanbul</a></em>. Sadly it doesn&#8217;t work just out of the box, because the coverage calculations and tests aren&#8217;t run in the same JS engine. The tests run in Firefox and the calculations happen outside in NodeJS.<span id="more-3057"></span></p>
<p>By default Istanbul uses a global variable to store the coverage information. The problem begins with the CommonJS environment of the Add-on SDK not having a global environment. To work around that, I&#8217;ve made <a href="https://github.com/freaktechnik/istanbul-jpm/blob/master/global.js">a module</a> that exports an object which istanbul then treats as its global object. But to do that, the <em>Instrumenter</em>, the thing that makes your code inspectable during unit tests, has to be modified to use that module instead of the Node global. Luckily this is just a modification of one line in a function in the prototype of the Instrumenter. This happens in the <a href="https://github.com/freaktechnik/istanbul-jpm/blob/master/index.js">main module</a> of the <em><a href="https://www.npmjs.com/package/istanbul-jpm">istanbul-jpm</a></em> package, which I created.</p>
<pre class="brush: jscript; title: ; notranslate">
/* The second item in the array differs from the normal
 * Instrumenter, everything else is the same. */
code = &#x5B;
    &quot;%STRICT%&quot;,
    &quot;var %VAR% = require('istanbul-jpm/global').global;&quot;,
    &quot;if (!%VAR%.%GLOBAL%) { %VAR%.%GLOBAL% = {}; }&quot;,
    &quot;%VAR% = %VAR%.%GLOBAL%;&quot;,
    &quot;if (!(%VAR%&#x5B;'%FILE%'])) {&quot;,
    &quot;   %VAR%&#x5B;'%FILE%'] = %OBJECT%;&quot;,
    &quot;}&quot;,
    &quot;%VAR% = %VAR%&#x5B;'%FILE%'];&quot;
]
</pre>
<p>Having a custom module providing the &#8220;global&#8221; scope also makes bridging the gap between Firefox and Node really easy. It just serializes the &#8220;global&#8221; object when the extension is unloaded (after all unit tests are done) and writes it to disk. Funnily enough the module is called <em>global</em>. There is a module for node that then reads and parses that file called <em>global-node</em>.</p>
<pre class="brush: jscript; title: ; notranslate">
/* Loading the collected coverage data into the node
 * environment. */
global.__coverage__ = require(&quot;istanbul-jpm/global-node&quot;).global.__coverage__;
</pre>
<p>Only the <em>global.js</em> from the istanbul-jpm package is needed during unit tests, everything else can safely be .jpmignored. Sadly you have to do that yourself, since JPM doesn&#8217;t respect the <em>.jpmignore</em> files from extensions.</p>
<p>And that&#8217;s all the extra magic needed. The rest is magic that needs to happen whenever you collect coverage data. But because generating coverage statistics is quite complicated I&#8217;ll explain the other steps too:</p>
<p>Before the unit tests are ran, the Instrumenter adds the tracking logic to your modules (normally everything in your <em>lib</em> folder and maybe in your root). I haven&#8217;t bothered to figure out a way to do coverage analysis for content scripts, by the way.</p>
<p>But for coverage data to be collected the modules generated by the Instrumenter have to be loaded in the unit tests and not the normal modules. Common practice is to create a require-helper module, that checks an environment variable and either loads the module from its actual location or redirects it to the instrumented version.</p>
<p>An example implementation for instrumented modules being in the <em>/coverage/instrument/lib/</em> folder, the following code does exactly what is described in the previous paragraph. If the environment variable <code>JPM_MEASURING_COVERAGE</code> is set, it redirects to the instrumented versions.</p>
<pre class="brush: jscript; title: ; notranslate">
const system = require(&quot;sdk/system&quot;);

module.exports = function (path) {
    if(system.env.JPM_MEASURING_COVERAGE)
        return require('../coverage/instrument/test/' + path);
    else
        return require(path);
};
</pre>
<p>After the unit tests a report has to be generated. This can have many forms, and really depends on what you want to do with coverage statistics.</p>
<p>I use grunt to manage all of this, a bootsrapped <em>Gruntfile.js</em> can be found in the <a href="https://www.npmjs.com/package/istanbul-jpm#example-usage-with-grunt-istanbul"><em>README,md</em> of the istanbul-jpm module</a>. There is also the monstrosity, that is the <a href="https://github.com/freaktechnik/justintv-stream-notifications/blob/master/Gruntfile.js"><em>Gruntfile.js</em> of my jtvn extension</a>.</p>
<p>The <a href="https://www.npmjs.com/package/istanbul-jpm">istanbul-jpm</a> module helps close the gap between the normal Node environment and JPM tests for coverage analysis with istanbul. It&#8217;s pretty young, but there&#8217;s not much that can go wrong. Give it a try!</p>
<p>The post <a href="https://humanoids.be/log/2015/11/checking-code-coverage-of-add-on-sdk-extensions/">Checking Code Coverage of Add-on SDK Extensions</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3057</post-id>	</item>
		<item>
		<title>Testing Add-on SDK Extensions on Travis CI</title>
		<link>https://humanoids.be/log/2015/08/testing-add-on-sdk-extensions-on-travis-ci/</link>
		
		<dc:creator><![CDATA[Martin Giger]]></dc:creator>
		<pubDate>Mon, 17 Aug 2015 09:51:32 +0000</pubDate>
				<category><![CDATA[Add-on SDK]]></category>
		<category><![CDATA[add-on]]></category>
		<category><![CDATA[add-on sdk]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[ci]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[firefox for android]]></category>
		<category><![CDATA[jetpack]]></category>
		<category><![CDATA[mozilla]]></category>
		<category><![CDATA[test]]></category>
		<category><![CDATA[travis]]></category>
		<category><![CDATA[unit tests]]></category>
		<guid isPermaLink="false">http://humanoids.be/log/?p=3014</guid>

					<description><![CDATA[<img width="700" height="293" src="https://humanoids.be/log/wp-content/uploads/2015/08/travisci-1038x434.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2015/08/travisci-1038x434.png 1038w, https://humanoids.be/log/wp-content/uploads/2015/08/travisci-474x198.png 474w, https://humanoids.be/log/wp-content/uploads/2015/08/travisci.png 1233w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3025" data-permalink="https://humanoids.be/log/2015/08/testing-add-on-sdk-extensions-on-travis-ci/travisci/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2015/08/travisci.png" data-orig-size="1233,515" data-comments-opened="0" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="travisci" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2015/08/travisci-474x198.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2015/08/travisci-1038x434.png" /><p>Recently Mozilla restricted access to ftp.mozilla.org, instead you can download nightlies from archive.mozilla.org. Sadly this broke existing methods to download Firefox nightly for automated unit tests on Travis CI. I&#8217;ve written a node module, that takes care of downloading nightly versions of Firefox desktop and Android. .travis.yml for Desktop sudo: false language: node_js node_js: stable &#8230; </p>
<p class="link-more"><a href="https://humanoids.be/log/2015/08/testing-add-on-sdk-extensions-on-travis-ci/" class="more-link">Continue reading<span class="screen-reader-text"> "Testing Add-on SDK Extensions on Travis CI"</span></a></p>
<p>The post <a href="https://humanoids.be/log/2015/08/testing-add-on-sdk-extensions-on-travis-ci/">Testing Add-on SDK Extensions on Travis CI</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<img width="700" height="293" src="https://humanoids.be/log/wp-content/uploads/2015/08/travisci-1038x434.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="display: block; margin: auto; margin-bottom: 5px;max-width: 100%;" link_thumbnail="" decoding="async" loading="lazy" srcset="https://humanoids.be/log/wp-content/uploads/2015/08/travisci-1038x434.png 1038w, https://humanoids.be/log/wp-content/uploads/2015/08/travisci-474x198.png 474w, https://humanoids.be/log/wp-content/uploads/2015/08/travisci.png 1233w" sizes="auto, (max-width: 700px) 100vw, 700px" data-attachment-id="3025" data-permalink="https://humanoids.be/log/2015/08/testing-add-on-sdk-extensions-on-travis-ci/travisci/" data-orig-file="https://humanoids.be/log/wp-content/uploads/2015/08/travisci.png" data-orig-size="1233,515" data-comments-opened="0" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="travisci" data-image-description="" data-image-caption="" data-medium-file="https://humanoids.be/log/wp-content/uploads/2015/08/travisci-474x198.png" data-large-file="https://humanoids.be/log/wp-content/uploads/2015/08/travisci-1038x434.png" /><p>Recently Mozilla restricted access to ftp.mozilla.org, instead you can download nightlies from <a href="https://archive.mozilla.org">archive.mozilla.org</a>. Sadly this broke existing methods to download Firefox nightly for automated unit tests on <a href="https://travis-ci.org">Travis CI</a>. I&#8217;ve written a node module, that takes care of downloading nightly versions of Firefox desktop and Android.<span id="more-3014"></span></p>
<h2>.travis.yml for Desktop</h2>
<pre class="brush: yaml; title: ; notranslate">sudo: false
language: node_js
node_js: stable
env:
  global:
    - DISPLAY=:99.0
    - JPM_FIREFOX_BINARY=$TRAVIS_BUILD_DIR/../firefox/firefox
before_install:
  - sh -e /etc/init.d/xvfb start
  - npm i -g get-firefox
  - get-firefox -ecb unbranded-release -t ../
before_script:
  - npm install -g jpm
script:
  - jpm test</pre>
<p><em>Update:</em> I changed the export commands to setting the variables with the .travis.yml env property, because it feels cleaner.</p>
<p><em>Update 2</em>: Switched to the <a href="http://docs.travis-ci.com/user/firefox/">Firefox from travis</a>.</p>
<p><em>Update 3:</em> With unsigned builds being a thing and travis not supporting them yet, I&#8217;ve switched back to using get-firefox for desktop tests too.</p>
<h2>.travis.yml for Android</h2>
<p>Since jpm-mobile is currently broken, this clones a fixed version and installs it. Further, timing for the Android Emulator is somewhat important, so you might have to fiddle with the order and content of the before sections.</p>
<pre class="brush: yaml; title: ; notranslate">sudo: false
language: android
android:
  components:
    - platform-tools
    - tools
    - android-19
    - sys-img-armeabi-v7a-android-19
env:
  global:
    - DISPLAY=99.0
    - JPM_FIREFOX_BINARY=fennec
    - JPM_ADB_PATH=/usr/local/android-sdk/platform-tools/adb
    - TMP_DIR=/tmp
before_install:
  - sh -e /etc/init.d/xvfb start
  - mkdir -p $TMP_DIR/sdcard
  - mksdcard -l jetpackSdCard 1024M $TMP_DIR/sdcard/jpmsdcard.img
  - rm -f $TMP_DIR/sdcard/jpmsdcard.img.lock
  - echo no | android create avd --force -n jpm -t android-19 --abi armeabi-v7a
  - emulator -avd jpm -sdcard $TMP_DIR/sdcard/jpmsdcard.img -no-audio -gpu off -no-boot-anim -noskin &amp;amp;
  - android-wait-for-emulator
before_script:
  - npm install -g get-firefox
  - git clone --depth 1 -b fixes https://github.com/ncalexan/jpm-mobile.git $TMP_DIR/jpm-mobile
  - cd $TMP_DIR/jpm-mobile
  - npm link
  - cd $TRAVIS_BUILD_DIR
  - get-firefox -c -p android -t $TMP_DIR/fennec.apk
  - adb wait-for-device
  - adb emu input keyevent 82 &amp;amp;amp;
  - adb install $TMP_DIR/fennec.apk
script:
  - jpm-mobile test -v --adb $JPM_ADB_PATH -b $JPM_FIREFOX_BINARY</pre>
<p>The post <a href="https://humanoids.be/log/2015/08/testing-add-on-sdk-extensions-on-travis-ci/">Testing Add-on SDK Extensions on Travis CI</a> appeared first on <a href="https://humanoids.be/log">Humanoids beLog</a>.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3014</post-id>	</item>
	</channel>
</rss>
