<?xml version="1.0" encoding="utf-8" standalone="no"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0" xml:base="https://www.blue-bag.com">
<channel>
 <title>Blue-Bag - Information Systems</title>
 <link>https://www.blue-bag.com</link>
 <description>Web design and development and bespoke information system development. Data and feed integration and modelling.</description>
 <language>en</language>
<item>
 <title>Drupal - My view has a null module dependency</title>
 <link>https://www.blue-bag.com/blog/drupal-my-view-has-null-module-dependency</link>
 <description>&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;div class="panel-body"&gt;
&lt;p class="lead"&gt;We often get asked to troubleshoot issues on Drupal sites and recently, twice in succession on different Drupal 8 sites, we came across an issue where a configuration file contained the word &lt;em&gt;null&lt;/em&gt; in its list of module dependencies.&lt;/p&gt;
&lt;div class="wel"&gt;
&lt;pre&gt;dependencies:
  module:
    - null
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="lead"&gt;This was causing a number of issues and is clearly wrong. When trying to import configuration for example you are faced with a problem because Drupal thinks the configuration relies on a module called &lt;em&gt;null&lt;/em&gt; which clearly doesn't, and never did, exist.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="panel-body clearfix alert alert-info"&gt;
&lt;h4&gt;So just create a module called 'NULL' - Problem solved :p&lt;/h4&gt;
&lt;p&gt;There actually is a Drupal contributed module 'null' that is provided specifically to overcome this issue - but it effectively &lt;em&gt;null routes&lt;/em&gt; the error by providing a module called null to match the dependency - it addresses the symptoms not the cause - &lt;a href="https://www.drupal.org/project/null"&gt;https://www.drupal.org/project/null&lt;/a&gt; - if you are in a desperate hurry to move on with your life then that &lt;em&gt;might&lt;/em&gt; be for you - if you want to solve the cause read on.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;If this does happen to you then you will have problems importing configuration and in our case the view whose configuration file was affected also raised an error when being saved.&lt;/p&gt;
&lt;div class="panel-body clearfix"&gt;
&lt;pre&gt;Notice: Undefined index: table in Drupal\views\Plugin\views\relationship\RelationshipPluginBase-&amp;gt;calculateDependencies()
(line 179 of core/modules/views/src/Plugin/views/relationship/RelationshipPluginBase.php).&lt;/pre&gt;&lt;/div&gt;
&lt;div class="panel-body"&gt;
&lt;div class="col-md-6"&gt;
&lt;h3&gt;Let's investigate&lt;/h3&gt;
&lt;p&gt;I thought it would be a good opportunity to write up the investigation as I didn't find a lot of similar issue when Googling and I am sure &lt;a href="https://imgs.xkcd.com/comics/wisdom_of_the_ancients.png" onclick="window.open(this.href, '', 'resizable=no,status=no,location=no,toolbar=no,menubar=no,fullscreen=no,scrollbars=no,dependent=no,width=485,left=50%,height=270,top=50%'); return false;"&gt;I'll come back here at somepoint myself&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is relevant to &lt;span class="label label-primary"&gt;Drupal 8&lt;/span&gt; and &lt;span class="label label-primary"&gt;Drupal 9&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In the scenario that follows the site had a custom module that is used to attach Promotions to line items. The module creates a number of tables for this purpose and declares a schema to describe the tables and their fields. These tables and some of their fields are used in the affected view.&lt;/p&gt;
&lt;p&gt;So what is going on! - Why is the configuration writing null as a dependency?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="col-md-6"&gt;
&lt;p&gt;The view's configuration file contained the following excerpt:&lt;/p&gt;
&lt;div class="wel"&gt;
&lt;pre&gt;uuid: 12345678-1234-5678-ab9ba-9876d54cba32
langcode: en
status: true
dependencies:
  module:
    - null
    - csv_serialization
    - mycustom_schema
    - rest
    - serialization
    - user
    - views_autocomplete_filters
    - views_data_export
    - views_date_format_sql&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="panel-body"&gt;
&lt;div class="col-md-6"&gt;
&lt;h4&gt;Custom schema tables&lt;/h4&gt;
&lt;p&gt;The tables in this case are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A custom line item table&lt;/li&gt;
&lt;li&gt;A table to contain data about promotions and&lt;/li&gt;
&lt;li&gt;A join table to link them (I have simplified this for illustration)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The view surfaces some of the fields from the Line Item and Promotion tables and it all works ok in the view - but when you save the view you get:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="col-md-6 wel"&gt;
&lt;pre&gt;+---------------+                     +--------------+
|               |                     |              |
|  Line Item    |                     |  Promotion   |
|               |                     |              |
+-------+-------+                     +-------+------+
        |                                     |
        |                                     |
        |    +-----------------------+        |
        |    |                       |        |
        +---&amp;gt;|   LineItemPromotion   &amp;lt;--------+
             |                       |
             +-----------------------+&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="panel-body clearfix"&gt;
&lt;pre&gt;Notice: Undefined index: table in Drupal\views\Plugin\views\relationship\RelationshipPluginBase-&amp;gt;calculateDependencies()
(line 179 of core/modules/views/src/Plugin/views/relationship/RelationshipPluginBase.php).&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But the view works.&lt;/p&gt;
&lt;h3&gt;Roll up your sleeves&lt;/h3&gt;
&lt;p&gt;So how do we troubleshoot this and find out what is causing the issues:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You get an error when you save the view,&lt;/li&gt;
&lt;li&gt;The config for the view has null in the name of a dependency and&lt;/li&gt;
&lt;li&gt;You can't import the configuration&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first thing to check is if the schema of the data model is implemented correctly in the modules install file in&lt;/p&gt;
&lt;div class="panel-body"&gt;
&lt;pre&gt;hook_schema()&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is where you define the schema so the tables get created when the module is installed. When investigating this it became apparent that the tables were modified in subsequent and successive updates (adding new fields and indexes etc)&lt;/p&gt;
&lt;div class="panel-body"&gt;
&lt;pre&gt;hook_update_N()&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As it happens, although the schema was updated by these updates, the module schema itself was not updated - this was not the source of our problems, but would be a problem when the module was installed in the future.&lt;/p&gt;
&lt;p&gt;see &lt;a href="https://www.drupal.org/docs/drupal-apis/update-api/updating-database-schema-andor-data-in-drupal-8"&gt;Updating Database Schema and/or Data in Drupal 8 (www.drupal.org/docs/drupal-apis/update-api/updating-database-schema-andor-data-in-drupal-8)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You should always update the schema with such updates.&lt;/p&gt;
&lt;h3&gt;Plugin Dependencies&lt;/h3&gt;
&lt;p&gt;But fixing that does not solve our specific issue. Furthermore, our module &lt;em&gt;&lt;strong&gt;is&lt;/strong&gt;&lt;/em&gt; present in the list of dependencies for the view and the view works (although it errors when saved and we can't import the configuration). So we need to see why Views can't work out the dependency and places a null in the config.&lt;/p&gt;
&lt;p&gt;To do this we need to understand how Views determines the dependencies and see what the actual source of the error is - maybe not our module after all?&lt;/p&gt;
&lt;p&gt;When the configuration for a view is written, Views calculates the dependencies of fields and other things (plugins) used in the view. It does this in &lt;em&gt;&lt;strong&gt;RelationshipPluginBase&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;
&lt;div class="panel-body clearfix"&gt;
&lt;pre&gt;web/core/modules/views/src/Plugin/views/relationship/RelationshipPluginBase.php
abstract class RelationshipPluginBase extends HandlerBase {

  .... other stuff removed for readability ....
172:   /**
173:    * {@inheritdoc}
174:    */
175:   public function calculateDependencies() { 
176:     $dependencies = parent::calculateDependencies();
177:     // Add the provider of the relationship's base table to the dependencies.
178:     $table_data = $this-&amp;gt;getViewsData()-&amp;gt;get($this-&amp;gt;definition['base']);
179:     $dependencies['module'][] = $table_data['table']['provider'];
180:     return $dependencies;
181:   }
182:
183:}
184:
185:/**
186: * @}
187: */&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is called for all of the plugins (fields in our case) required by the view and this in turn calls &lt;em&gt;&lt;strong&gt;getViewData()&lt;/strong&gt;&lt;/em&gt; to find out which module each plugin comes from, to build up a list of dependencies.&lt;/p&gt;
&lt;p&gt;When we come to line 178 we go off to &lt;em&gt;web/core/modules/views/src/ViewsData.php&lt;/em&gt; which looks at all modules that implement hook_views_data() to see which is the originator of the plugin.&lt;/p&gt;
&lt;div class="panel-body"&gt;
&lt;pre&gt;235:   protected function getData() {
236:     $this-&amp;gt;fullyLoaded = TRUE;
237: 
238:     if ($data = $this-&amp;gt;cacheGet($this-&amp;gt;baseCid)) {
238:       return $data-&amp;gt;data;
239:     }
240:     else {
241:       $modules = $this-&amp;gt;moduleHandler-&amp;gt;getImplementations('views_data');
242:       $data = [];
243:       foreach ($modules as $module) {
244:         $views_data = $this-&amp;gt;moduleHandler-&amp;gt;invoke($module, 'views_data');
245:         // Set the provider key for each base table.
246:         foreach ($views_data as &amp;amp;$table) {
247:           if (isset($table['table']) &amp;amp;&amp;amp; !isset($table['table']['provider'])) {
248:             $table['table']['provider'] = $module;
249:           }
250:         }
251:         $data = NestedArray::mergeDeep($data, $views_data);
252:       }
253:       $this-&amp;gt;moduleHandler-&amp;gt;alter('views_data', $data);
254: 
255:      $this-&amp;gt;processEntityTypes($data);
256: 
257:       // Keep a record with all data.
258:       $this-&amp;gt;cacheSet($this-&amp;gt;baseCid, $data);
259: 
260:       return $data;
261:     }
262:   }&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From line 244 on it gets a list of tables for all modules that implement hook_views_data and looks for the table name from the plugin.&lt;/p&gt;
&lt;p&gt;If none is found it returns an empty $data and this causes the error:&lt;/p&gt;
&lt;div class="panel-body"&gt;
&lt;pre&gt;Undefined index: table&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;when the RelationshipPluginBase (line 179) is called resulting in 'null' being returned as a dependency.&lt;/p&gt;
&lt;p&gt;So in our case we find that when looking for the module that implements the table (&lt;em&gt;mycustom_schema_line_item_promo&lt;/em&gt;) we are returned 'null' since it is not found.&lt;/p&gt;
&lt;p&gt;The other tables and more importantly the fields they display in the view results are fine.&lt;/p&gt;
&lt;p&gt;So we need to investigate the implementation of the hook_views_data in the custom module.&lt;/p&gt;
&lt;h3&gt;Declare which tables you own&lt;/h3&gt;
&lt;p&gt;What we find is that the tables (&lt;em&gt;mycustom_schema_line_item&lt;/em&gt; and &lt;em&gt;mycustom_schema_promo&lt;/em&gt;) whose fields are in the view (and correctly return the module as the dependency) are defined in the module; as are their relationship with the join table. But, the join table itself is not declared in the hook_views_data() and therefore views can't figure out which module it is dependent on.&lt;/p&gt;
&lt;p&gt;The following extracts from this hook implementation show how they are declared:&lt;/p&gt;
&lt;p&gt;For brevity I have omitted the declarations of all of the fields for the tables (and other custom tables).&lt;/p&gt;
&lt;div class="panel-body"&gt;
&lt;pre&gt;// The line item custom table
  $data['mycustom_schema_line_item']['table']['group'] = t('Custom Line Item');

  $data['mycustom_schema_line_item']['table']['base'] = [
    'title' =&amp;gt; t('Custom Line Items'),
    'help' =&amp;gt; t('Custom Line Items provided by the Custom module.'),
  ];

  // ID.
  $data['mycustom_schema_line_item']['id'] = [
    'title' =&amp;gt; t('Line Item ID'),
    'help' =&amp;gt; t('Line item unique identifier.'),
    'field' =&amp;gt; [
      'id' =&amp;gt; 'numeric',
    ],
    'sort' =&amp;gt; [
      'id' =&amp;gt; 'standard',
    ],
    'filter' =&amp;gt; [
      'id' =&amp;gt; 'numeric',
    ],
  ];

  // The field to link in the promo.
  $data['mycustom_schema_line_item']['promo'] = [
    'title' =&amp;gt; t('Promotion'),
    'help' =&amp;gt; t('The names of the promotions applied to this order.'),
    'relationship' =&amp;gt; [
      'base' =&amp;gt; 'mycustom_schema_line_item_promo',
      'base field' =&amp;gt; 'line_item_id',
      'field' =&amp;gt; 'id',
      'id' =&amp;gt; 'standard',
      'label' =&amp;gt; t('Promotion'),
    ],
  ];


  $data['mycustom_schema_promo']['table']['group'] = t('Custom Promotion');

  $data['mycustom_schema_promo']['name'] = [
    'title' =&amp;gt; t('Promotion'),
    'help' =&amp;gt; t('The name of the promotion reference.'),
    'field' =&amp;gt; [
      'id' =&amp;gt; 'standard',
    ],
    'sort' =&amp;gt; [
      'id' =&amp;gt; 'standard',
    ],
    'filter' =&amp;gt; [
      'id' =&amp;gt; 'string',
    ],
  ];

  // the join details to link the join table to the promo table
  $data['mycustom_schema_promo']['table']['join'] = [
    'mycustom_line_item_promo' =&amp;gt; [
      'left_field' =&amp;gt; 'promo_id',
      'field' =&amp;gt; 'id',
    ],
  ];

return $data;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;So although the relationships are defined here (interestingly in two different ways - but let's not get distracted) there is no definition for the link table (&lt;em&gt;mycustom_line_item_promo&lt;/em&gt;) itself.&lt;/p&gt;
&lt;p&gt;So when Views calculates the dependencies, it can find the details for the Line item table (&lt;em&gt;mycustom_schema_line_item&lt;/em&gt;) and Promotions table (&lt;em&gt;mycustom_schema_promo&lt;/em&gt;) and their fields but not for the join table (&lt;em&gt;mycustom_schema_line_item_promo&lt;/em&gt;) so can't determine which module it is dependent upon.&lt;/p&gt;
&lt;p&gt;We need to add some metadata for that table to the hook_views_data().&lt;/p&gt;
&lt;div class="panel-body"&gt;
&lt;pre&gt; 
....  
  
  // in our case all we need to add some table meta data so views can see we 'own' the table
  $data['mycustom_schema_line_item_promo']['table']['group'] = t('Custom Promotion');
  
  $data['mycustom_schema_line_item_promo']['table']['base'] = [
    'title' =&amp;gt; t('Custom Line Items - Link to promotions'),
    'help' =&amp;gt; t('Custom Line Item promotions provided by the Custom module.'),
  ];
  // why not the fields too? Maybe because we don't want them to be included in views results?
  $data['mycustom_line_item_promo']['id'] = [
    'title' =&amp;gt; t('Line Item Promo ID'),
    'help' =&amp;gt; t('Line item promo unique identifier.'),
    'field' =&amp;gt; [
      'id' =&amp;gt; 'numeric',
    ],
    'sort' =&amp;gt; [
      'id' =&amp;gt; 'standard',
    ],
    'filter' =&amp;gt; [
      'id' =&amp;gt; 'numeric',
    ],
  ];
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once this is added and caches are flushed (the dependency data are cached in the ViewsData getData() so this is important) the view can be saved without error, the config no longer contains a null dependency (it already had the dependency for our module obtained from the other tables that were declared) and we can import the config.&lt;/p&gt;
&lt;p&gt;Hopefully this will point others in the right direction if they face the same issue. Of course it might not be Views at the heart of your issue - if you have faced this issue let me know in the comments.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-category field-type-taxonomy-term-reference field-label-above"&gt;&lt;div class="field-label"&gt;Category:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/technology/drupal" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;Drupal&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-image field-type-image field-label-above"&gt;&lt;div class="field-label"&gt;Blog image:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" class="img-responsive" src="https://www.blue-bag.com/sites/default/files/blogimage/config-null-module_0.png" width="228" height="248" alt="NULL Module dependency" title="NULL Module dependency" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Thu, 01 Jul 2021 16:16:12 +0000</pubDate>
 <dc:creator>George Boobyer</dc:creator>
 <guid isPermaLink="false">142 at https://www.blue-bag.com</guid>
</item>
<item>
 <title>BOM disposal</title>
 <link>https://www.blue-bag.com/blog/bom-disposal</link>
 <description>&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;Occassionally when you get files from someone else or use a new text editor you encounter an issue with hidden characters or incorrect encoding that can be a pain to track down.&lt;/p&gt;
&lt;p&gt;A common one of these that I haven't encountered for ages, (since we moved from Windows to OSX for development) is the Byte Order Mark (BOM).&lt;/p&gt;
&lt;p&gt;This is a simple marker that indicates the encoding order of UTF-8 files and should in itself be no problem. It does however cause an issue when the file is included within other files (by PHP as&lt;em&gt; *.inc&lt;/em&gt; files for example) such as in template files.&lt;/p&gt;
&lt;p&gt;This can result in blank lines that are hard to track down or problems with page headers.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;You may also find that the BOM causes problems for an ordinary PHP page. When sending custom HTTP headers the code to set the header must be called before output begins. A BOM at the start of the file causes the page to begin output before the header command is interpreted, and may lead to error messages and other problems in the displayed page.&lt;br /&gt;&lt;a href="https://www.w3.org/International/questions/qa-byte-order-mark"&gt;https://www.w3.org/International/questions/qa-byte-order-mark&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It was exactly that issue that I encountered the other day and being such a blast from the past - I thought I would make this quick post about the issue and some ways of tracking it down and fixing it.&lt;/p&gt;
&lt;p&gt;So, first off what issue does it cause. Well in my case and in past cases too it caused Drupal to complain and create a circular redirect on admin pages. &lt;/p&gt;
&lt;p&gt;This is illustrated by errors such as the 'headers already being sent’ error (&lt;a href="https://www.drupal.org/node/1424"&gt;https://www.drupal.org/node/1424&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;In fact it was that error that jogged my memory on the subject as I hadn't seen it for a long time.&lt;/p&gt;
&lt;p&gt;The cause was an old module template file that I hadn't done any work on for a few years since moving from Windows development environment.&lt;/p&gt;
&lt;p&gt;So in this case I was thrown a bone as that was obviously the latest change to the site.&lt;/p&gt;
&lt;p&gt;In other cases however it can be tricky to track down - so lets look at what it is and how to locate and remove it.&lt;/p&gt;
&lt;p&gt;You can search your files for BOMs (limiting the search to the first line, as the character sequence may appear elsewhere and it is only the first characters of the first line that we are interested in).&lt;/p&gt;
&lt;pre&gt;grep -rl '\xEF\xBB\xBF' . &lt;/pre&gt;&lt;p&gt;on MACOSX you need to prepend a dollar sign:&lt;/p&gt;
&lt;pre&gt;grep -rlI $'\xEF\xBB\xBF' .&lt;/pre&gt;&lt;p&gt;Note the full stop is required to indicate the files in the current directory.&lt;/p&gt;
&lt;p&gt;We could remove this en masse with a script - but this may cause issues if the file is supposed to have them:&lt;/p&gt;
&lt;pre&gt;sed 's/\xEF\xBB\xBF//' &amp;lt; inputfile &amp;gt; outputfile&lt;/pre&gt;&lt;p&gt;again on MAC oSX (note the $ )&lt;/p&gt;
&lt;pre&gt;sed $'s/\xEF\xBB\xBF//' &amp;lt; inputfile &amp;gt; outputfile&lt;/pre&gt;&lt;p&gt;Note that these will remove the first instance (if you wanted to remove every instance - not adviseable - but as 'sed' note - use the global modifier 'g').&lt;/p&gt;
&lt;p&gt;However unless you have loads of them it is likely to be only a single file that is causing an issue - so lets open that and see what it looks like.&lt;/p&gt;
&lt;pre&gt;vim file.html

&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&amp;gt;&lt;/pre&gt;&lt;p&gt;Although the BOM is the first sequence of charatcetrs in the file - the BOM is not displayed by defauklt in most text editors. This makes them hard to locate/assess.&lt;/p&gt;
&lt;p&gt;But you can open the file in VIM in binary mode::&lt;/p&gt;
&lt;pre&gt;vim -b file.html

&amp;lt;feff&amp;gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&amp;gt;&lt;/pre&gt;&lt;p&gt;Note the &amp;lt;feff&amp;gt; char sequence. &lt;/p&gt;
&lt;p&gt;When looking at the file in VIM in normal text mode you can check if there is a BOM:&lt;/p&gt;
&lt;pre&gt;:setlocal bomb? 
​bomb&lt;/pre&gt;&lt;p&gt;And get it to save without the BOM&lt;/p&gt;
&lt;pre&gt;:setlocal nobomb 
:w &lt;/pre&gt;&lt;p&gt;Most text editors allow you to set a a global option to not set the BOM.&lt;/p&gt;
&lt;p&gt;See the attached Asciiinema of a terminal session showing these steps (or go here &lt;a href="https://asciinema.org/a/46517" rel="noopener noreferrer" target="_blank" title="Screencast"&gt;https://asciinema.org/a/46517&lt;/a&gt;).&lt;/p&gt;
&lt;script type="text/javascript" src="https://asciinema.org/a/46517.js" id="asciicast-46517" async=""&gt;&lt;/script&gt;&lt;p&gt;&lt;noscript&gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;img src="/i/howtos/BOMdisposal.gif" /&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&lt;/noscript&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;props:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://stackoverflow.com/a/12220257"&gt;http://stackoverflow.com/a/12220257&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://vim.1045645.n5.nabble.com/How-to-display-and-remove-BOM-in-utf-8-encoded-file-td4681708.html"&gt;http://vim.1045645.n5.nabble.com/How-to-display-and-remove-BOM-in-utf-8-encoded-file-td4681708.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://stackoverflow.com/a/29490814"&gt;http://stackoverflow.com/a/29490814&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-category field-type-taxonomy-term-reference field-label-above"&gt;&lt;div class="field-label"&gt;Category:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/technology/drupal" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;Drupal&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-image field-type-image field-label-above"&gt;&lt;div class="field-label"&gt;Blog image:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" class="img-responsive" src="https://www.blue-bag.com/sites/default/files/blogimage/bomdisposal1_0.gif" width="592" height="396" alt="Finding and disposing of BOM" title="Finding and disposing of BOM" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Tue, 24 May 2016 08:41:56 +0000</pubDate>
 <dc:creator>George Boobyer</dc:creator>
 <guid isPermaLink="false">137 at https://www.blue-bag.com</guid>
</item>
<item>
 <title>Stock for Drupal 8 commerce - Technical overview &amp; use cases</title>
 <link>https://www.blue-bag.com/blog/stock-drupal-8-commerce-technical-overview-use-cases</link>
 <description>&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;h2&gt;The business requirements&lt;/h2&gt;
&lt;p&gt;Drawing on the experience of maintaining the Drupal 7 stock module and working with a number of ERPs over the years we have come up with a completely new architecture for Drupal 8 commerce stock module.&lt;/p&gt;
&lt;p&gt;The following are the 4 main challenges that I encountered with the Drupal 7 module that needed addressing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Performance issues including deadlocks&lt;/li&gt;
&lt;li&gt;The need for a mature transactional based system&lt;/li&gt;
&lt;li&gt;Location based stock&lt;/li&gt;
&lt;li&gt;Integrate with external ERP systems.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the same time it was important to me to make sure the module is suitable for the majority of the stock module users that were happy with the simple approach of the Drupal 7 version.&lt;br /&gt;In so doing we have made it easy for others to extend.&lt;/p&gt;
&lt;p&gt;The result is a proposed architecture that addresses all these and has been presented over the last year through the drupal.org &lt;a href="https://www.drupal.org/project/commerce_stock"&gt;commerce stock issue queue&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;The Service architecture&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;StockAvailabilityChecker&lt;/strong&gt; - This implements the core commerce &lt;strong&gt;AvailabilityCheckerInterface&lt;/strong&gt; and, once this interface is implemented in commerce, it will provide the stock checking functionality.&lt;br /&gt;This service doesn’t do much in itself as it uses the StockManager to do the work.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;StockManager&lt;/strong&gt; - This is a service collector that collects services of type &lt;strong&gt;StockServiceInterface&lt;/strong&gt;. It also holds a configuration class that tells it when to use this service.&lt;br /&gt;Currently the configuration will allow for selecting one active service but at a later stage this will be extended to work at a more granular level (probably by product type).&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Stock service&lt;/strong&gt; - The module comes with two services: The first is an &lt;strong&gt;"Always in stock"&lt;/strong&gt; and the second is the &lt;strong&gt;"Transactional Stock"&lt;/strong&gt; currently called "Local Stock" (i.e. stored in the drupal DB).  &lt;br /&gt;Each stock service needs to implement 3 classes based on the following interfaces: &lt;strong&gt;StockCheckInterface&lt;/strong&gt;, &lt;strong&gt;StockUpdateInterface&lt;/strong&gt; &amp;amp; &lt;strong&gt;StockConfigurationInterface&lt;/strong&gt;.&lt;br /&gt;The Configuration determines the relevant location(s). The checker does the availability checking and the Update the updating.&lt;/p&gt;
&lt;h2&gt;&lt;br /&gt;&lt;br /&gt;The Transactional Stock Service&lt;/h2&gt;
&lt;p&gt;This is designed to provide full audit capabilities on current stock levels, far better tracking and reporting and improved performance across multiple locations (warehouses, stores, ...)&lt;br /&gt;The idea is that each stock movement (sold products, new stock ..) will result in a transaction record. This record will hold a quantity along side other information.    &lt;br /&gt;These records can be summed up by product variation to get the overall stock level.&lt;br /&gt;The advantage of this system is that by using only selects and inserts we get a highly efficient db system that can not result in deadlocks (a common D7 stock issue). The potential problem is that large number of transactions can be expensive to sum. The solution for this problem is a cron job that will periodically sum existing transactions and update a master record with the totaled quantity alongside the last transaction id. This introduces an update but as this is handled by a single process (cron) we are not introducing a potential deadlock so the result should provide performance and scalability.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;The state of things&lt;/h2&gt;
&lt;p&gt;The current implementation of the Drupal 8 module available on drupal.org provides a complete service architecture and it's the Stock service itself that is the focus of on going development.&lt;br /&gt;The transactional stock service implements an API capable of creating transactions and running availability checks, so once we have an interface (currently only a dev one is available) &amp;amp; commerce implements the availably Checker we should have a working system.   &lt;br /&gt;However the following need implementing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The cron job for updating the location stock&lt;/li&gt;
&lt;li&gt;UI for creating and managing stock locations &amp;amp; transactions. Currently a development sub module for calling API functions is included but will be removed when the first beta is realised.&lt;/li&gt;
&lt;li&gt;Transaction Metadata holding information for each transaction - In progress to be finished shortly.&lt;/li&gt;
&lt;li&gt;Unit Cost - The transaction record includes a unit_cost field for for FIFO and LIFO reporting.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;br /&gt;Use cases&lt;/h2&gt;
&lt;p&gt;The plan is to sub-class the current service "local Stock" into two services that will be almost identical but serve two use cases.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Transactional stock&lt;/strong&gt; - A full transactional service or a 'non watered down version' of "local Stock"&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simple stock&lt;/strong&gt; - This will use the "local stock" functionality but delete transactions after they are totalled to avoid holding a large dataset when one is not needed. It is likely to include a more simplified interface and possibly be limited to a single location.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other use cases for the module are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;External ERP integration&lt;/strong&gt; - New services can be developed for specific ERP systems I am hoping to develop the Brightpearl one see &lt;a href="https://www.drupal.org/project/commerce_brightpearl"&gt;https://www.drupal.org/project/commerce_brightpearl&lt;/a&gt; in time for a full release.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Other use cases and customisation&lt;/strong&gt; - The combination of a the service architecture + the fact that Drupal 8 is OOP will allow people to derive their own services from existing ones as well as developing a complete solution to be plugged into the StockManager.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;How can I help?&lt;/h2&gt;
&lt;p&gt;If you have an interest in inventory management or just want to help make Drupal and Drupal Commerce better do get involved with the issue queue.&lt;/p&gt;
&lt;p&gt;for more details see &lt;a href="https://www.drupal.org/project/commerce_stock"&gt;https://www.drupal.org/project/commerce_stock &lt;/a&gt;and &lt;a href="https://www.drupal.org/node/2618906"&gt;Stock for D8: Architecture &amp;amp; high level functionality&lt;/a&gt; in the drupal.org issue Q&lt;br /&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-category field-type-taxonomy-term-reference field-label-above"&gt;&lt;div class="field-label"&gt;Category:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/technology/drupal" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;Drupal&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item odd"&gt;&lt;a href="/technology/e-commerce" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;e-commerce&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Wed, 11 May 2016 11:52:05 +0000</pubDate>
 <dc:creator>Guy Schneerson</dc:creator>
 <guid isPermaLink="false">136 at https://www.blue-bag.com</guid>
</item>
<item>
 <title>Drupal 8 Release</title>
 <link>https://www.blue-bag.com/blog/drupal-8-release</link>
 <description>&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;On the 19th November 2015 a new version of the Drupal content management system (CMS) will be released - Drupal 8.&lt;/p&gt;
&lt;p&gt;This new version has been over four years in development and has seen contributions from over &lt;a href="http://pages.ctidigital.com/drupalcon-drupal8-hall-of-fame" target="_blank"&gt;three thousand people&lt;/a&gt;. It contains well over &lt;a href="https://www.drupal.org/drupal-8.0"&gt;200 new features&lt;/a&gt;, uses object orientated code and is probably the most significant release to date.&lt;/p&gt;
&lt;p&gt;There will be over 200 release parties around the world on the 19th; a series of events that will bring the Drupal community together to mark this new release and discuss the opportunities and implications of the most powerful versuin of Drupal yet. See a map of all of the event - &lt;a href="http://www.drupical.com/"&gt;http://www.drupical.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Drupal Somerset (&lt;a href="https://twitter.com/drupalsomerset"&gt;@drupalsomerset&lt;/a&gt;) is planning on holding it's own release party in Glastonbury to join in this global celebration.&lt;/p&gt;
&lt;p&gt;If you are in the area and would like to attend then let us know &lt;a href="https://twitter.com/drupalsomerset"&gt;@drupalsomerset&lt;/a&gt; on twitter or contact us through this website's contact form.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.indigo-herbs.co.uk"&gt;Indigo-herbs&lt;/a&gt; has kindly offered to host the event at their new development offices in Glastonbury:&lt;/p&gt;
&lt;p&gt;Indigo Herbs&lt;br /&gt;Unit 8&lt;br /&gt;Adlams Central Park&lt;br /&gt;Wirrall Park Road&lt;br /&gt;GLASTONBURY&lt;br /&gt;BA6 9XE&lt;/p&gt;
&lt;p&gt;The plan is to meet at 19:00. There will be refreshments and the opportunity for a range of discussions around the following topics.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What’s new in D8&lt;/li&gt;
&lt;li&gt;Getting ready for Drupal 8&lt;/li&gt;
&lt;li&gt;Trying Drupal 8 out: Getting Drupal 8 set up on a VM&lt;/li&gt;
&lt;li&gt;When should I think about using D8 in my new projects&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These won't be formal presentations - but more an opportunity to discuss these topics with a range of people; of which some have already used Drupal 8 and others who have not yet had the chance.&lt;/p&gt;
&lt;p&gt;Everyone is welcome to attend.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-category field-type-taxonomy-term-reference field-label-above"&gt;&lt;div class="field-label"&gt;Category:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/technology/drupal" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;Drupal&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-image field-type-image field-label-above"&gt;&lt;div class="field-label"&gt;Blog image:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" class="img-responsive" src="https://www.blue-bag.com/sites/default/files/blogimage/drupal-8-logo-stacked.png" width="500" height="513" alt="Drupal 8 Release" title="Drupal 8 Release" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Tue, 17 Nov 2015 15:38:18 +0000</pubDate>
 <dc:creator>George Boobyer</dc:creator>
 <guid isPermaLink="false">132 at https://www.blue-bag.com</guid>
</item>
<item>
 <title>Compiling Varnish modules</title>
 <link>https://www.blue-bag.com/blog/compiling-varnish-modules</link>
 <description>&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;Varnish is a powerful tool and although simple to get running initially can have a steep learning curve beyond the initial install.&lt;/p&gt;
&lt;p&gt;In this post I look at compiling a Varnish module and some issues you may face and how to overcome them.&lt;/p&gt;
&lt;p&gt;When implementing Varnish, sometimes you want to cache pages for a 'test' site or a site that isn't open to the public yet.&lt;/p&gt;
&lt;p&gt;Typically you would use basic authentication on the Apache server and have Varnish not cache pages that require authentication.&lt;/p&gt;
&lt;p&gt;But if you do want Varnish to cache pages for a 'closed' site then you have to move authentication to Varnish.&lt;/p&gt;
&lt;p&gt;There are two modules that support this -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;basic authentication: which works like basic authentication in Apache and can use the same htpasswd files - &lt;a href="https://www.varnish-cache.org/vmod/basicauth"&gt;https://www.varnish-cache.org/vmod/basicauth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;authentication - that uses hases of user:passwrd in the vcl itself. - &lt;a href="https://www.varnish-cache.org/vmod/authentication"&gt;https://www.varnish-cache.org/vmod/authentication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I recently evaluated the basic authentication module:   &lt;a href="https://www.varnish-cache.org/vmod/basicauth"&gt;https://www.varnish-cache.org/vmod/basicauth&lt;/a&gt; -  source: &lt;a href="http://git.gnu.org.ua/cgit/vmod-basicauth.git/"&gt;http://git.gnu.org.ua/cgit/vmod-basicauth.git/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The first problem I faced was the scant documentation about how to use Varnish modules.&lt;/p&gt;
&lt;div&gt;&lt;em&gt;tl;dr - Get the source for the module and Varnish, build Varnish and then build the module against the Varnish source.&lt;/em&gt;&lt;/div&gt;
&lt;p&gt;I came across a detailed explanation of how to do this here : &lt;a href="http://stackoverflow.com/questions/28163273/varnish-4-basic-authentication"&gt;http://stackoverflow.com/questions/28163273/varnish-4-basic-authentication&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In order to be able to use a Varnish module you need clone the module from source and compile it against the Varnish source.&lt;/p&gt;
&lt;p&gt;To do this you have to get the Varnish source (and many dependencies)  and build it (although you don't have to install it if you have already done so via your package manager).&lt;/p&gt;
&lt;pre&gt;$agt-get source varnish&lt;/pre&gt;&lt;p&gt;To build Varnish from source follow the instructions here: &lt;a href="https://www.varnish-cache.org/docs/trunk/installation/install.html"&gt;https://www.varnish-cache.org/docs/trunk/installation/install.html&lt;/a&gt; and make sure you have the dependencies listed for your platform.&lt;/p&gt;
&lt;p&gt;However the issue I faced was that the Varnish source would not compile.&lt;/p&gt;
&lt;p&gt;This was due to the automake functionality not recursing into subdirectories.&lt;/p&gt;
&lt;pre class="shell"&gt;warning: source file &amp;lt;some source file&amp;gt; is in a subdirectory,
but option 'subdir-objects' is disabled&lt;/pre&gt;&lt;p&gt;To solve this you have to add the subdir-options option to the automake in line 18 of the configure.ac:&lt;/p&gt;
&lt;pre&gt;$vi /usr/src/varnish-4.0.3/configure.ac

AM_INIT_AUTOMAKE([1.11 foreign color-tests parallel-tests &lt;strong&gt;&lt;em&gt;subdir-options&lt;/em&gt;&lt;/strong&gt;])&lt;/pre&gt;&lt;p&gt;However with this option there is an issue (on Debian at least) whereby variable expansion fails in the make files in the bin directory for the Varnish programs (varnishadm and varnishhist). (see &lt;a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=402727"&gt;https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=402727&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;To solve this you have to edit the Makefile.am files in the varnishadm and varnishhist bin folders:&lt;/p&gt;
&lt;pre&gt;$vi bin/varnishadm/Makefile.am
&lt;/pre&gt;&lt;pre&gt;varnishadm_SOURCES = \
	varnishadm.c \
	$(top_srcdir)/lib/libvarnish/vas.c \
	$(top_srcdir)/lib/libvarnish/vsa.c \
	$(top_srcdir)/lib/libvarnish/vtcp.c \
	$(top_srcdir)/lib/libvarnish/vss.c&lt;/pre&gt;&lt;pre&gt;varnishadm_SOURCES = \
	varnishadm.c \
	../../lib/libvarnish/vas.c \
	../../lib/libvarnish/vsa.c \
	../../lib/libvarnish/vtcp.c \
	../../lib/libvarnish/vss.c&lt;/pre&gt;&lt;p&gt;Otherwise when you run the make command, the build will fail and you will have subfolders in the bin/varnishadm folder called $(top_srcdir).&lt;/p&gt;
&lt;p&gt;This only appears to affect the SOURCES element. - see &lt;a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=402727"&gt;https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=402727&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once that is done - you can build the varnish source and then compile and install your module as outlined in &lt;a href="http://stackoverflow.com/questions/28163273/varnish-4-basic-authentication"&gt;http://stackoverflow.com/questions/28163273/varnish-4-basic-authentication&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-category field-type-taxonomy-term-reference field-label-above"&gt;&lt;div class="field-label"&gt;Category:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/technology/varnish" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;varnish&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-image field-type-image field-label-above"&gt;&lt;div class="field-label"&gt;Blog image:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" class="img-responsive" src="https://www.blue-bag.com/sites/default/files/blogimage/varnish-cache.jpg" width="319" height="195" alt="Varnish Cache" title="Varnish Cache" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Mon, 09 Nov 2015 13:57:51 +0000</pubDate>
 <dc:creator>George Boobyer</dc:creator>
 <guid isPermaLink="false">131 at https://www.blue-bag.com</guid>
</item>
<item>
 <title>Ansible filters for taming lists (part 1)</title>
 <link>https://www.blue-bag.com/blog/ansible-filters-taming-lists-part-1</link>
 <description>&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;When running through a series of tasks in Ansible it is common to want to have data available in a few formats - sometimes as a simple list and sometimes as a dictionary. What we don't really want to do is to have the same data in two or more separate lists (that would be hard to maintain).&lt;br /&gt;
So say I have a task that updates a series of images on the remote host and I need the data in the format - &lt;/p&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;{ src: filename, type: filetype}&lt;/code&gt;&lt;/div&gt;
&lt;p&gt;But in another task I want a list of the types we updated. I don't want to have to manage two lists and I don't want to repeat an action if the types are duplicated across a number of file instances.&lt;br /&gt;
Ideally we would like to be able to get from the list a list of unique values from one of the elements - and that is where Jinja filters can help.&lt;br /&gt;
Firstly I am bound to say that Ansible is not a programming language, so we should always think of the simplest way to do this and not have loads of Jinja processing within a task.&lt;br /&gt;
Also in some cases it is worth considering creating/using a plugin to get the processing out of your tasks and templates (and that is the subject of part 2).&lt;br /&gt;
So back to the task - Lets consider a fictitious scenario. I have a site that has pictures of fruit and you can download archives of all of the images of fruit combined  by type. A routine on the server builds archives for the fruit types that contain all of the images of fruit of that type. So I can request a download of a zip containing all citrus fruit images or all non citrus fruit images. These archives are cached so they don't have to be built more than once - but the cached files need to be dropped if more fruit images are added.&lt;br /&gt;
Occasionally I want to upload more fruity pictures and when I do that I want to drop the archives for the type (so they will get rebuilt when next requested). But I don't want to maintain two vars; one for the list of images and one for the list of types of archive to drop. What I want is one list of fruit images that lists the name of the files and the type of the fruit.&lt;br /&gt;
So I could easily use a &lt;em&gt;with_items&lt;/em&gt; iterator for both a copy task (to put up the images) and the drop archive task (file state=absent), but that would repeat the second task necessarily.&lt;br /&gt;
So I create a dictionary var for the fruit images:&lt;/p&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;images_to_update:&lt;br /&gt;      - { name: "oranges-001.jpg", type: "Citrus"}&lt;br /&gt;      - { name: "oranges-002.jpg", type: "Citrus"}&lt;br /&gt;      - { name: "apples-001.jpg", type: "Non-citrus"}&lt;br /&gt;      - { name: "bananas-001.jpg", type: "Non-citrus"}&lt;br /&gt;      - { name: "grapes-001.jpg", type: "Non-citrus"}&lt;br /&gt;      - { name: "grapefruit-001.jpg", type: "Citrus"}&lt;br /&gt;      - { name: "pears-001.jpg", type: "Non-citrus"}&lt;/code&gt;&lt;/div&gt;
&lt;p&gt;and then create one task to use a &lt;em&gt;with_items&lt;/em&gt; to copy each of these up to the server.&lt;br /&gt;
Then I use a filter to set a fact (a new variable that persists only during the scope of the play) to create a unique list of the type values so that I can drop the relevant archives.&lt;br /&gt;
This uses the filter:&lt;/p&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;fruit_archives_to_drop: "{{images_to_update|map(attribute='type')|list|unique }}"&lt;/code&gt;&lt;/div&gt;
&lt;p&gt;This says take the dictionary structure (images_to_update) and create a list from the 'type' attribute and further make it unique - Cool huh! You can then use this generated list to iterate without repetition.&lt;/p&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;"['Citrus', 'Non-citrus']"&lt;/code&gt;&lt;/div&gt;
&lt;p&gt;See a working demo of this in the gist below.&lt;br /&gt;
In the next part I will show how we can use this sort of thing to get a list of unique IPs from your inventory (hostvars) to add to a firewall whitelist or similar in partnership with a plug-in.&lt;/p&gt;
&lt;script src="https://gist.github.com/iAugur/aced8b964392519654c9.js"&gt;&lt;/script&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-category field-type-taxonomy-term-reference field-label-above"&gt;&lt;div class="field-label"&gt;Category:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/technology/ansible" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;Ansible&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item odd"&gt;&lt;a href="/technology/yaml" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;YAML&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item even"&gt;&lt;a href="/technology/jinja2" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;jinja2&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-image field-type-image field-label-above"&gt;&lt;div class="field-label"&gt;Blog image:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" class="img-responsive" src="https://www.blue-bag.com/sites/default/files/blogimage/ansible-list-filters-ninja.png" width="400" height="263" alt="Ansible lists and filters" title="Ansible lists and filters" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Fri, 27 Mar 2015 16:08:47 +0000</pubDate>
 <dc:creator>George Boobyer</dc:creator>
 <guid isPermaLink="false">123 at https://www.blue-bag.com</guid>
</item>
<item>
 <title>YAML Death by non-breaking spaces</title>
 <link>https://www.blue-bag.com/blog/yaml-death-non-breaking-spaces</link>
 <description>&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;Just when you are in the flow of it - something comes up that spoils your mood.&lt;br /&gt;
So that I don't forget and hopefully as a note for anyone else tripped up by this.&lt;br /&gt;
Today a long play that I have been working on for some time suddenly started to fail with the message:&lt;/p&gt;
&lt;div class="codeblock"&gt;&lt;code&gt;Traceback (most recent call last):&lt;br /&gt;  File "/usr/local/Cellar/ansible/1.8.4_1/libexec/bin/ansible-playbook", line 326, in &amp;lt;module&amp;gt;&lt;br /&gt;    sys.exit(main(sys.argv[1:]))&lt;br /&gt;  File "/usr/local/Cellar/ansible/1.8.4_1/libexec/bin/ansible-playbook", line 266, in main&lt;br /&gt;    pb.run()&lt;br /&gt;  File "/usr/local/Cellar/ansible/1.8.4_1/libexec/lib/python2.7/site-packages/ansible/playbook/__init__.py", line 313, in run&lt;br /&gt;    play = Play(self, play_ds, play_basedir, vault_password=self.vault_password)&lt;br /&gt;  File "/usr/local/Cellar/ansible/1.8.4_1/libexec/lib/python2.7/site-packages/ansible/playbook/play.py", line 165, in __init__&lt;br /&gt;    self._tasks      = self._load_tasks(self._ds.get('tasks', []), load_vars)&lt;br /&gt;  File "/usr/local/Cellar/ansible/1.8.4_1/libexec/lib/python2.7/site-packages/ansible/playbook/play.py", line 636, in _load_tasks&lt;br /&gt;    data = utils.parse_yaml_from_file(include_filename, vault_password=self.vault_password)&lt;br /&gt;  File "/usr/local/Cellar/ansible/1.8.4_1/libexec/lib/python2.7/site-packages/ansible/utils/__init__.py", line 786, in parse_yaml_from_file&lt;br /&gt;    process_yaml_error(exc, data, path, show_content)&lt;br /&gt;  File "/usr/local/Cellar/ansible/1.8.4_1/libexec/lib/python2.7/site-packages/ansible/utils/__init__.py", line 719, in process_yaml_error&lt;br /&gt;    %s""" % (path, mark.line + 1, mark.column + 1, before_probline, probline, arrow)&lt;br /&gt;UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128)&lt;/code&gt;&lt;/div&gt;
&lt;p&gt;This horrible error message was quite hard to debug - not because it isn't obvious as to what has happened (the last line says it all) - a stray extended character - dopey key press - has crept into one of my yaml files - but because the character was hard to track down.&lt;br /&gt;
It turned out to be a non-breaking space entered by mistake by option-space (a key press that normally brings up iTerm in visor mode - so not a mistake I make very often).&lt;br /&gt;
&lt;img align="right" style="padding:4px" src="/i/howtos/ansible-non-breaking-space-yaml.gif" alt="non breaking spaces and yaml don't mix" /&gt;By turning on 'show invisibles' it still may not show up as it looks like a space. So hunting these things down can be hard.&lt;br /&gt;
So in my case a simple non breaking space (U+00A0) tripped me up.&lt;br /&gt;
But by re-tracing your steps and checking the encoding of your recently changed files (commit often!) hopefully you will spot such things before heading off on a goose chase.&lt;br /&gt;
Anyhow - putting it up here so I remember and hopefully to help some other poor passer by!&lt;br /&gt;
Here is a good resource for decoding such issues - &lt;a href="http://rishida.net/tools/conversion/"&gt;http://rishida.net/tools/conversion/&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-category field-type-taxonomy-term-reference field-label-above"&gt;&lt;div class="field-label"&gt;Category:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/technology/ansible" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;Ansible&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item odd"&gt;&lt;a href="/technology/yaml" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;YAML&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-image field-type-image field-label-above"&gt;&lt;div class="field-label"&gt;Blog image:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;img typeof="foaf:Image" class="img-responsive" src="https://www.blue-bag.com/sites/default/files/blogimage/ansible-non-breaking-ninja.png" width="400" height="263" alt="non breaking spaces break python yaml" title="non breaking spaces break python yaml" /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Thu, 19 Mar 2015 14:49:14 +0000</pubDate>
 <dc:creator>George Boobyer</dc:creator>
 <guid isPermaLink="false">122 at https://www.blue-bag.com</guid>
</item>
<item>
 <title>Using Ansible to protect against 'Connection attempts using mod_proxy'</title>
 <link>https://www.blue-bag.com/blog/using-ansible-protect-against-connection-attempts-using-modproxy</link>
 <description>&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;p&gt;I regularly encounter issues that arise from reviews of server security, log reviews etc that provide good examples of how Ansible can be used to respond to an issue.&lt;br /&gt;
Once such example is making sure that all of your servers are protected from being used as a Proxy.&lt;br /&gt;
In our case we use Ansible to provision and monitor the configuration of our servers and we have a set of playbooks that secure our servers and set up security applications and firewalls to ensure they are not vulnerable.&lt;br /&gt;
A common set up is to secure you servers with IPTables and Fail2ban and use Logwatch to monitor your logs for common signs of unwanted activity. You should monitor these reports regularly and respond to any unusual activity; in most cases these should already be protected against.&lt;br /&gt;
But if you are using a utility like Logwatch to keep an eye on activity on your servers you may occasionally see an entry such as&lt;/p&gt;
&lt;pre&gt;
   Connection attempts using mod_proxy:
   1.164.40.29 -&amp;gt; mx3.mail2000.com.tw:25: 1 Time(s)
&lt;/pre&gt;&lt;p&gt;This indicates that someone is scanning your server to see if they are able to use it as a Proxy to attach to a mail server or some other service. This is definitely not wanted and it is worth checking that your are not vulnerable to this exploit.&lt;br /&gt;
By default, Apache has ProxyRequests set to Off and doesn't by default install with the proxy modules enabled - but it is worthwhile checking to ensure that that is the case.&lt;br /&gt;
To do so by hand would involve something like the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Visit every server and check that the relevant modules are disabled.&lt;/li&gt;
&lt;li&gt;Limit use of the CONNECT verb to ensure that such connections are denied.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That can be time consuming and you would need to do it regularly to ensure that the module is not enabled later on.&lt;/p&gt;
&lt;p&gt;So using Ansible we can do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Provide a list of modules we always want to see disabled on a server and create a task that will ensure they are disabled.&lt;/li&gt;
&lt;li&gt;Provide a default configuration file on the server to limit use of the CONNECT verb and create a task that puts that in the correct place and restarts the web server. Note that the examples will require adaptation for some distros (i.e. Centos) and will require a handler for the Apache restart. In most cases these would be additions to your existuing playbook for controlling your web servers.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Doing it this way :&lt;/p&gt;
&lt;ol type="a"&gt;
&lt;li&gt;Documents the change to your build spec&lt;/li&gt;
&lt;li&gt;Applies the measure to all servers.&lt;/li&gt;
&lt;li&gt;Maintains the state of the measure&lt;/li&gt;
&lt;li&gt;Enables you to extend how you respond to the issue&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So we create a variables list (apache_mods_disabled) that contains all of the modules we want to be sure are disabled. &lt;/p&gt;
&lt;pre&gt;
---
- hosts: webservers
vars:
apache_mods_disabled:
- proxy
- proxy_ftp
- proxy_http
- proxy_connect
&lt;/pre&gt;&lt;p&gt;We then use this list in a task that disables the modules if they are enabled (and does nothing if they are already disabled).&lt;/p&gt;
&lt;pre&gt;
 - name: Apache | Disable Apache Mods
   apache2_module: state=absent name={{ item }}
   with_items: apache_mods_disabled
   notify: restart apache
&lt;/pre&gt;&lt;p&gt;We also create a small configuration file to limit the Connect verb and place that in the conf.d folder (read in by Apache on a restart) &lt;/p&gt;
&lt;pre&gt;
# {{ ansible_managed }}
&amp;lt;Location /&amp;gt;
&amp;lt;Limit CONNECT&amp;gt;
Order deny,allow
Deny from all
&amp;lt;/Limit&amp;gt;
&amp;lt;/Location&amp;gt;
&lt;/pre&gt;&lt;p&gt;and place that on the server using the template module. &lt;/p&gt;
&lt;pre&gt;
 - name: Apache | Limit Connect verb
   template: src=apache_conf_connect.j2 dest=/etc/apache2/conf.d/proxy_connect.conf
   notify: restart apache
&lt;/pre&gt;&lt;p&gt;Each of these tasks will notify a handler to restart Apache if needed.&lt;br /&gt;
Typically you would simple add the variables and tasks to your existing playbooks.&lt;br /&gt;
You can the be confident that the protection measure is in place on all of your web servers and that state is maintained.&lt;br /&gt;
See a full Gist here: &lt;/p&gt;
&lt;script src="https://gist.github.com/iAugur/a9bd6e224e8065eeaa22.js"&gt;&lt;/script&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="field field-name-field-blog-category field-type-taxonomy-term-reference field-label-above"&gt;&lt;div class="field-label"&gt;Category:&amp;nbsp;&lt;/div&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even"&gt;&lt;a href="/technology/ansible" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;Ansible&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item odd"&gt;&lt;a href="/technology/apache" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;Apache&lt;/a&gt;&lt;/div&gt;&lt;div class="field-item even"&gt;&lt;a href="/technology/security" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype=""&gt;Security&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Mon, 13 Oct 2014 09:43:26 +0000</pubDate>
 <dc:creator>George Boobyer</dc:creator>
 <guid isPermaLink="false">118 at https://www.blue-bag.com</guid>
</item>
<item>
 <title>The Team</title>
 <link>https://www.blue-bag.com/node/6</link>
 <description>&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;div class="team"&gt;
&lt;div class="section-title text-center"&gt;
&lt;h2&gt;The Team&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="col-sm-5 rp20"&gt;&lt;figure&gt;&lt;img alt="The team" src="/sites/default/files/i/about.jpg" /&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div class="col-sm-7"&gt;
&lt;p class="lead"&gt;In 2000 Blue-Bag was created by George Boobyer and Guy Schneerson to pool their experience and expertise.&lt;/p&gt;
&lt;p&gt;Both George and Guy had been working for many years developing Information systems for a wide variety of clients and platforms. In 2010 we took the decision to move to open source technologies and moved away from proprietary and bespoke Windows based software and IIS/ .Net based web site development. Since then we have specialised in providing Drupal solutions on Linux hosting. This has enabled us to provide extremely competitive solutions that fit our customer's needs and don't tie them down to us as a provider - Our clients stay with us because they want to not because they have to!&lt;/p&gt;
&lt;p&gt;Although we are based in the UK we have undertaken development work for clients across the globe from the USA to Russia.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Tue, 23 Sep 2014 10:44:40 +0000</pubDate>
 <dc:creator>bb-admin</dc:creator>
 <guid isPermaLink="false">6 at https://www.blue-bag.com</guid>
</item>
<item>
 <title>Our Clients</title>
 <link>https://www.blue-bag.com/node/5</link>
 <description>&lt;div class="field field-name-body field-type-text-with-summary field-label-hidden"&gt;&lt;div class="field-items"&gt;&lt;div class="field-item even" property="content:encoded"&gt;&lt;div class="our-clients"&gt;
&lt;div class="section-title"&gt;
&lt;h2&gt;trusted by&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="col-lg-3 col-md-3 col-sm-6"&gt;&lt;img class="img-thumbnail" alt="Dickies Europe" src="/sites/default/files/i/clients/our-clients-dickies.png" /&gt;&lt;/div&gt;
&lt;div class="col-lg-3 col-md-3 col-sm-6"&gt;&lt;img class="img-thumbnail" alt="Victoria and Albert Museum" src="/sites/default/files/i/clients/our-clients-vanda.png" /&gt;&lt;/div&gt;
&lt;div class="col-lg-3 col-md-3 col-sm-6"&gt;&lt;img class="img-thumbnail" alt="Kew Gardens" src="/sites/default/files/i/clients/our-clients-kew.png" /&gt;&lt;/div&gt;
&lt;div class="col-lg-3 col-md-3 col-sm-6"&gt;&lt;img class="img-thumbnail" alt="History of Parliament" src="/sites/default/files/i/clients/our-clients-hop.png" /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</description>
 <pubDate>Tue, 23 Sep 2014 10:43:53 +0000</pubDate>
 <dc:creator>bb-admin</dc:creator>
 <guid isPermaLink="false">5 at https://www.blue-bag.com</guid>
</item>
</channel>
</rss>