<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title></title>
    <description>I love to solve problems - often with software, always with tea.</description>
    <link>https://meikle.io/</link>
    <atom:link href="https://meikle.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Mon, 07 Nov 2022 21:10:06 +0000</pubDate>
    <lastBuildDate>Mon, 07 Nov 2022 21:10:06 +0000</lastBuildDate>
    <generator>Jekyll v4.2.1</generator>
    
      <item>
        <title>Development SSL for .NET Core and NGINX in Docker</title>
        <description>&lt;figure class=&quot;aligncenter&quot;&gt;
    &lt;img alt=&quot;padlock on door latch&quot; src=&quot;/assets/img/james-sutton-FqaybX9ZiOU-unsplash.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;i&gt;&lt;span&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jamessutton_photography?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;James Sutton&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/secure?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;
  &lt;/span&gt;&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;We’ve all been there. You want to use SSL in development to mirror a production setup but it’s a pain to generate self-signed
certificates, share them with the development team, and have them trusted locally.&lt;/p&gt;

&lt;p&gt;Thankfully combining &lt;em&gt;Docker&lt;/em&gt; and the &lt;em&gt;dotnet dev-certs&lt;/em&gt; command makes this nice and easy for .NET Core Applications and NGINX - 
which I’m sharing here so I don’t forget :)&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;net-dev-certs-command&quot;&gt;.NET Dev Certs Command&lt;/h2&gt;

&lt;p&gt;To make it easier for developers to generate and access development SSL certificates, the .NET Core provides
the &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-dev-certs&quot;&gt;&lt;em&gt;dotnet dev-certs&lt;/em&gt;&lt;/a&gt; command as part of the CLI experience.&lt;/p&gt;

&lt;p&gt;This command allows you to generate, export, trust and clean up self-signed developer certificates for your 
applications.&lt;/p&gt;

&lt;p&gt;The beauty of this command on Window is that it adds the certificate to the trusted store locally meaning
that browsers will validate it as such.&lt;/p&gt;

&lt;p&gt;By using this approach each developer can quickly generate their own certificates locally and mount them in Docker
as part of a &lt;em&gt;Docker Compose&lt;/em&gt; file.&lt;/p&gt;

&lt;h2 id=&quot;net-core-application&quot;&gt;.NET Core Application&lt;/h2&gt;

&lt;p&gt;.NET Core applications expect certificates in PFX format, so to generate a certificate in this format you can
use the &lt;em&gt;–format pfx&lt;/em&gt; option for the  &lt;em&gt;dotnet dev-certs&lt;/em&gt; command.&lt;/p&gt;

&lt;p&gt;Below is an example of generating a certificate into a &lt;em&gt;config&lt;/em&gt; folder:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;dotnet dev-certs https -ep ./config/app-certificate.pfx -p BlahBlah --trust --format pfx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This command will then create a new certificate and trust it in the machines certificate store, before exporting it
to the PFX file, with the private key protected by the password &lt;em&gt;BlahBlah&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Having done this, we can then mount this certificate as a volume in Docker and set some environment variables
to configure the .NET Core application to use this certificate:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;app:
  build:
    context: app/.
    dockerfile: Dockerfile
  ports:
    - &quot;50000:50000&quot;
  environment:
    - ASPNETCORE_ENVIRONMENT=Development
    - ASPNETCORE_URLS=https://+:50000
    - ASPNETCORE_Kestrel__Certificates__Default__Password=BlahBlah
    - ASPNETCORE_Kestrel__Certificates__Default__Path=/certs/app-certificate.pfx
  volumes:
    - ./config/app-certificate.pfx:/certs/app-certificate.pfx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Voila! We have our .NET Core application listening on Port 50000 secured using SSL.&lt;/p&gt;

&lt;h2 id=&quot;nginx-docker-image&quot;&gt;NGINX Docker Image&lt;/h2&gt;

&lt;p&gt;In many cases your application will be running on HTTP with a reverse proxy in front of it, such
as NGINX.&lt;/p&gt;

&lt;p&gt;To use a similar approach with the NGINX docker image, you can use the &lt;em&gt;–format pem&lt;/em&gt; option 
for the  &lt;em&gt;dotnet dev-certs&lt;/em&gt; command to generate a key pair (i.e. crt and key files) in the PEM format.&lt;/p&gt;

&lt;p&gt;Below is an example of generating a certificate pair into a &lt;em&gt;config&lt;/em&gt; folder:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;dotnet dev-certs https -ep ./config/certificate.crt -np --trust --format pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this example, the &lt;em&gt;-np&lt;/em&gt; flag has been used to export the private key in the PEM file without the need
for a password to be provided to read it.&lt;/p&gt;

&lt;p&gt;In this approach, the NGINX config file can be updated to used these keys in it’s appropriate server block:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;listen              443 ssl;
server_name localhost;
ssl_certificate     /etc/nginx/proxy-certificate.crt;
ssl_certificate_key /etc/nginx/proxy-certificate.key;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If a password is desired, it can be provided in the export command:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;dotnet dev-certs https -ep ./config/certificate.crt -p BlahBlah --trust --format pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Doing this then requires you to pass a &lt;em&gt;ssl_password_file&lt;/em&gt; to NGINX using the &lt;a href=&quot;http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_password_file&quot;&gt;&lt;em&gt;ssl_password_file&lt;/em&gt;&lt;/a&gt; directive. For example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;listen              443 ssl;
server_name localhost;
ssl_certificate     /etc/nginx/proxy-certificate.crt;
ssl_certificate_key /etc/nginx/proxy-certificate.key;
ssl_password_file /etc/nginx/proxy-certificate.pass;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This file is just a simple text file with the password for the key inside it, or a list of passphrases to be tried, if you
wish to have one single password file for multiple certificates.&lt;/p&gt;

&lt;p&gt;Just like in the .NET Core Application example, these key files can be mounted as volumes:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;proxy:
    image: nginx
    ports:
     - &quot;80:80&quot;
     - &quot;443:443&quot;
    volumes:
      - ./config/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./config/proxy-certificate.crt:/etc/nginx/proxy-certificate.crt
      - ./config/proxy-certificate.key:/etc/nginx/proxy-certificate.key
    depends_on:
      - web-app
    links:
      - web-app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;refreshing-certificates&quot;&gt;Refreshing Certificates&lt;/h2&gt;

&lt;p&gt;If you want to start from scratch with a set of certificates, you can run the following command:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;dotnet dev-certs https --clean
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This clears down the https certificates.&lt;/p&gt;

</description>
        <pubDate>Wed, 03 Aug 2022 21:00:00 +0100</pubDate>
        <link>https://meikle.io/opensource/development-ssl-dotnetcore-docker.html</link>
        <guid isPermaLink="true">https://meikle.io/opensource/development-ssl-dotnetcore-docker.html</guid>
        
        <category>dotnetcore</category>
        
        <category>nginx</category>
        
        <category>docker</category>
        
        
        <category>opensource</category>
        
      </item>
    
      <item>
        <title>Okapi Maven Plugin</title>
        <description>&lt;figure class=&quot;aligncenter&quot;&gt;
    &lt;img alt=&quot;people looking at a laptop screen&quot; src=&quot;/assets/img/safar-safarov-MSN8TFhJ0is-unsplash.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;i&gt;&lt;span&gt;Photo by &lt;a href=&quot;https://unsplash.com/@codestorm?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Safar Safarov&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/code-on-a-laptop-screen?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;In the work we did at &lt;a href=&quot;https://www.lingo24.com&quot;&gt;Lingo24&lt;/a&gt; when I was there, we made use of the &lt;a href=&quot;https://okapiframework.org/&quot;&gt;Okapi Framework&lt;/a&gt; - well a customised fork - as a key component in our content processing.&lt;/p&gt;

&lt;p&gt;For those who don’t know the framework, it an excellent swiss-army like toolkit for localisation (l18n)/translation (t8n), which can be used either as a set of libraries or standalone tools.&lt;/p&gt;

&lt;p&gt;Whilst the tools available are great, often I wanted to bundle part of the process within an existing CI/CD pipeline or build. As a heavy Maven user, and with winter nights setting in, the idea came to build a Maven plugin to do just that.&lt;/p&gt;

&lt;p&gt;The result? The &lt;a href=&quot;https://github.com/dameikle/okapi-maven-plugin&quot;&gt;Okapi Maven Plugin&lt;/a&gt;.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-okapi-maven-plugin&quot;&gt;The Okapi Maven Plugin&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/dameikle/okapi-maven-plugin&quot;&gt;Okapi Maven Plugin&lt;/a&gt; is a Maven plugin that allows execution of common actions using the &lt;a href=&quot;http://okapiframework.org&quot;&gt;Okapi Framework&lt;/a&gt; within a Maven Project.&lt;/p&gt;

&lt;p&gt;It was inspired by the excellent &lt;a href=&quot;https://github.com/tingley/okapi-ant&quot;&gt;okapi-ant&lt;/a&gt; project, written by Chase Tingley, one of the core Okapi Framework team. (Hey Chase 👋🏻)&lt;/p&gt;

&lt;p&gt;Very much designed to scratch what was an immediate itch, it currently supports performing the following actions:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Execute a Pipeline&lt;/li&gt;
  &lt;li&gt;Export a Batch Configuration (BCONF)&lt;/li&gt;
  &lt;li&gt;Install a Batch Configuration (BCONF)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;using-the-okapi-maven-plugin&quot;&gt;Using the Okapi Maven Plugin&lt;/h3&gt;
&lt;p&gt;The plugin is being released on &lt;a href=&quot;https://central.sonatype.org&quot;&gt;Maven Central&lt;/a&gt;, so to use the plug-in you can simply include it in your project’s POM file in the plugins section.&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.meikle.maven.okapi&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;okapi-maven-plugin&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Configuration required here --&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;okapi-version&quot;&gt;Okapi Version&lt;/h3&gt;

&lt;p&gt;By default, the plugin uses the latest &lt;em&gt;Okapi Framework&lt;/em&gt; version, which at the time of writing this post is 1.43.0, with 1.44.0 coming soon.&lt;/p&gt;

&lt;p&gt;You can validate the version being used by running the &lt;em&gt;okapi:version&lt;/em&gt; goal.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mvn okapi:version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This can be changed by overriding the &lt;em&gt;Okapi Framework&lt;/em&gt;’s &lt;em&gt;okapi-core&lt;/em&gt; and &lt;em&gt;okapi-application-rainbow&lt;/em&gt; dependencies in the plugin configuration.&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.meikle.maven.okapi&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;okapi-maven-plugin&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                ...
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;net.sf.okapi&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;okapi-core&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.41.0&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;net.sf.okapi.applications&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;okapi-application-rainbow&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.41.0&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Exclude non-required UI dependencies --&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;exclusions&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;nt&quot;&gt;&amp;lt;exclusion&amp;gt;&lt;/span&gt;
                            &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;*&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                            &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.eclipse.platform&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/exclusion&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/exclusions&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;binary-configurations&quot;&gt;Binary Configurations&lt;/h3&gt;

&lt;p&gt;One of the main use cases for the plugin is to support the building of &lt;em&gt;Binary Configurations&lt;/em&gt;, also known as a &lt;em&gt;BCONF&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A BCONF is a single file binary bundle of a number of configuration items:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;i&gt;File Filter Settings&lt;/i&gt; - the settings on how a file is processed&lt;/li&gt;
  &lt;li&gt;&lt;i&gt;File Mappings&lt;/i&gt; - the mapping of file extensions to file filter settings&lt;/li&gt;
  &lt;li&gt;&lt;i&gt;Pipelines&lt;/i&gt; - the configurations determing the steps to be performed on the content&lt;/li&gt;
  &lt;li&gt;&lt;i&gt;Plugin JARs&lt;/i&gt; - optional JAR(s) with custom code, typically file filters or steps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ability to bundle them together in a single &lt;em&gt;BCONF&lt;/em&gt; them useful for sharing settings amongst colleagues, or when using the &lt;em&gt;Longhorn&lt;/em&gt; server application for executing Okapi Framework processing.&lt;/p&gt;

&lt;p&gt;Building &lt;em&gt;BCONF&lt;/em&gt; files can be done from the &lt;em&gt;Rainbow&lt;/em&gt; application interface provided by the Okapi Framework. To do this you configure the settings you want in the application and can then &lt;em&gt;export&lt;/em&gt; a configuration.&lt;/p&gt;

&lt;p&gt;The inverse process is also supported, allowing you to &lt;em&gt;import&lt;/em&gt; a configuration to a particular directory so it’s contents can be used within the application.&lt;/p&gt;

&lt;p&gt;To help with these operations, the &lt;em&gt;Okapi Maven Plugin&lt;/em&gt; allows you to build and install &lt;em&gt;BCONF&lt;/em&gt; files as part of your build.&lt;/p&gt;

&lt;h4 id=&quot;okapiexport&quot;&gt;okapi:export&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;export&lt;/em&gt; goal builds and export a Binary Configuration file and can be configured to package up configuration items in a number of scenarios.&lt;/p&gt;

&lt;p&gt;By default, the goal only has one mandatory parameter, &lt;em&gt;bconf&lt;/em&gt;. This is the name or path to where the Binary Configuration file should be exported to.&lt;/p&gt;

&lt;p&gt;The rest of the parameters are optional, allowing you to either package a pipeline and the filter mappings and/or plugins required to successfully execute it within Longhorn, or simply bundle a set configuration assets for sharing.&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Mandatory Name or Path to Export the BCONF to --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;bconf&amp;gt;&lt;/span&gt;export.bconf&lt;span class=&quot;nt&quot;&gt;&amp;lt;/bconf&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional Pipeline to be used in the BCONF --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;pipeline&amp;gt;&lt;/span&gt;test.pln&lt;span class=&quot;nt&quot;&gt;&amp;lt;/pipeline&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional Custom Filter Mapping(s) to be embedded in the BCONF --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;filterMappings&amp;gt;&lt;/span&gt; 
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;filterMapping&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- File extension to be mapped --&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;extension&amp;gt;&lt;/span&gt;.htm&lt;span class=&quot;nt&quot;&gt;&amp;lt;/extension&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Configuration to be used --&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;okf_html@test&lt;span class=&quot;nt&quot;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/filterMapping&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/filterMappings&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional Plugins to be included in the BCONF using Maven FileSet format- --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- See https://maven.apache.org/shared/file-management/fileset.html for more details --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional directory - can be absolute (include Maven variables), or relative to project baseDir --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- defaults to project baseDir --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;input&lt;span class=&quot;nt&quot;&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional - Includes or Excludes --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;includes&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;include&amp;gt;&lt;/span&gt;**/*.jar&lt;span class=&quot;nt&quot;&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/includes&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional output directory for the Okapi pipeline --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Defaults to the Maven target directory --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;outputDirectory&amp;gt;&lt;/span&gt;/tmp&lt;span class=&quot;nt&quot;&gt;&amp;lt;/outputDirectory&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;okapiinstall&quot;&gt;okapi:install&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;install&lt;/em&gt; goal installs a Binary Configuration file (a bconf) to a folder on the local machine so it can be used.&lt;/p&gt;

&lt;p&gt;The configuration for this goal has two mandatory items:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;bconf&lt;/em&gt; - the location of the BCONF file to install&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;outputDirectory&lt;/em&gt; - the folder to install the BCONF to&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;bconf&amp;gt;&lt;/span&gt;export.bconf&lt;span class=&quot;nt&quot;&gt;&amp;lt;/bconf&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;outputDirectory&amp;gt;&lt;/span&gt;/tmp/install-test&lt;span class=&quot;nt&quot;&gt;&amp;lt;/outputDirectory&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Both paths can be absolute or relative to the Maven Project’s &lt;em&gt;baseDir&lt;/em&gt;, which can be useful when chaining with the &lt;em&gt;pipeline&lt;/em&gt; goal.&lt;/p&gt;

&lt;h3 id=&quot;pipelines&quot;&gt;Pipelines&lt;/h3&gt;

&lt;p&gt;At the core of the Okapi Framework is the concept of a &lt;em&gt;pipeline&lt;/em&gt; - a list of actions in sequence that can be applied to or more input documents. Each action is a &lt;em&gt;step&lt;/em&gt; in Okapi parlance, which when chained together can build very powerful and complex translation workflows.&lt;/p&gt;

&lt;p&gt;Pipelines can be developed using the user interface in Okapi &lt;em&gt;Rainbow&lt;/em&gt; or via an XML format, with the framework supplying a significant library of out-of-the-box steps and pipelines for common actions in translation workflow. Like everything in Okapi, you can build your own steps.&lt;/p&gt;

&lt;p&gt;To help with executing pipelines, the &lt;em&gt;Okapi Maven Plugin&lt;/em&gt; allows you to execute pre-defined pipelines as part of your build.&lt;/p&gt;

&lt;h4 id=&quot;okapiexecute&quot;&gt;okapi:execute&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;execute&lt;/em&gt; goal executes a pipeline contained in a pipeline configuration file (a pln file) against the supplied input file(s).&lt;/p&gt;

&lt;p&gt;By default, the goal has four mandatory parameters:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;pipeline - the path to the pipeline file&lt;/li&gt;
  &lt;li&gt;inputFiles - the input files to process, defined using a FileSet&lt;/li&gt;
  &lt;li&gt;sourceLang - the source language name or code of the content&lt;/li&gt;
  &lt;li&gt;targetLang - the target language  name or code of the content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many other configuration options available to allow you to specify additional options for customised filter configurations, plugin locations, or override default locations. These can be useful if you are embedding your own custom assets into a build.&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Mandatory Path to pipeline to execute --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;pipeline&amp;gt;&lt;/span&gt;test.pln&lt;span class=&quot;nt&quot;&gt;&amp;lt;/pipeline&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Mandatory inputFiles using Maven FileSet format--&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- See https://maven.apache.org/shared/file-management/fileset.html for more details --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;inputFiles&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional directory - can be absolute (include Maven variables), or relative to project baseDir --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- defaults to project baseDir --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;input&lt;span class=&quot;nt&quot;&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional - Includes or Excludes --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;includes&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;include&amp;gt;&lt;/span&gt;**/*.txt&lt;span class=&quot;nt&quot;&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;include&amp;gt;&lt;/span&gt;**/*.md&lt;span class=&quot;nt&quot;&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/includes&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;excludes&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;exclude&amp;gt;&lt;/span&gt;**/*.xml&lt;span class=&quot;nt&quot;&gt;&amp;lt;/exclude&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/excludes&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/inputFiles&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Mandatory Source Language Name or Code--&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;sourceLang&amp;gt;&lt;/span&gt;English&lt;span class=&quot;nt&quot;&gt;&amp;lt;/sourceLang&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Mandatory Target Language Name or Code--&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;targetLang&amp;gt;&lt;/span&gt;fr-FR&lt;span class=&quot;nt&quot;&gt;&amp;lt;/targetLang&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional directory containing custom plugins --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Defaults to the project directory --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;pluginsDirectory&amp;gt;&lt;/span&gt;pluginsDir&lt;span class=&quot;nt&quot;&gt;&amp;lt;/pluginsDirectory&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional Explicit Plugins using Maven FileSet format- --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- See https://maven.apache.org/shared/file-management/fileset.html for more details --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional directory - can be absolute (include Maven variables), or relative to project baseDir --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- defaults to project baseDir --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;input&lt;span class=&quot;nt&quot;&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional - Includes or Excludes --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;includes&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;include&amp;gt;&lt;/span&gt;**/*.jar&lt;span class=&quot;nt&quot;&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/includes&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional directory containing custom filters --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Defaults to the project directory --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;filtersDirectory&amp;gt;&lt;/span&gt;filtersDir&lt;span class=&quot;nt&quot;&gt;&amp;lt;/filtersDirectory&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Optional output directory for the Okapi pipeline --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Defaults to the Maven target directory --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;outputDirectory&amp;gt;&lt;/span&gt;/tmp&lt;span class=&quot;nt&quot;&gt;&amp;lt;/outputDirectory&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;

&lt;p&gt;Whilst I moved on from Lingo24 before being able to use the plugin in anger, I have continued to use it for automating actions on some personal projects. I plan to keep evolving it as and when I get a chance, so would love feedback on what could be better or additional features that would be handy.&lt;/p&gt;

&lt;p&gt;Happy translating!&lt;/p&gt;
</description>
        <pubDate>Sat, 16 Jul 2022 08:00:00 +0100</pubDate>
        <link>https://meikle.io/localization/opensource/new-okapi-maven-plugin.html</link>
        <guid isPermaLink="true">https://meikle.io/localization/opensource/new-okapi-maven-plugin.html</guid>
        
        <category>okapi</category>
        
        <category>maven-plugin</category>
        
        
        <category>localization</category>
        
        <category>opensource</category>
        
      </item>
    
      <item>
        <title>Apache Tika Docker Examples</title>
        <description>&lt;figure class=&quot;aligncenter&quot;&gt;
    &lt;img alt=&quot;woman reading book whilst drinking coffee&quot; src=&quot;/assets/img/priscilla-du-preez-WWD93Icc30Y-unsplash.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;i&gt;
    &lt;span&gt;Photo by &lt;a href=&quot;https://unsplash.com/@priscilladupreez?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Priscilla Du Preez&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/learning?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/span&gt;
&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;For a number of years I’ve been involved in the Apache Tika project as both a committer and &lt;a href=&quot;https://www.apache.org/foundation/governance/pmcs&quot; target=&quot;_blank&quot;&gt;PMC&lt;/a&gt; member.&lt;/p&gt;

&lt;p&gt;With the increase in container technology usage over the past few years we spun up a separate repository for Apache Tika Server in Docker, called &lt;a href=&quot;https://github.com/apache/tika-docker&quot; target=&quot;_blank&quot;&gt;tika-docker&lt;/a&gt; with convenience images hosted on &lt;a href=&quot;https://hub.docker.com/r/apache/tika&quot; target=&quot;_blank&quot;&gt;Docker Hub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This has resulted in questions on how to customise configuration and host instances that link to other services. To help people get started, we’ve created some example scenarios.&lt;/p&gt;

&lt;p&gt;So let’s dive in and check them out.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-tika-docker-examples&quot;&gt;The tika-docker examples&lt;/h2&gt;

&lt;p&gt;To get the examples started, we’ve created examples using &lt;a href=&quot;https://docs.docker.com/compose/&quot; target=&quot;_blank&quot;&gt;Docker Compose&lt;/a&gt; of the following scenarios:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Recognising and Captioning Video and Images with TensorFlow REST (&lt;a href=&quot;https://github.com/apache/tika-docker/blob/master/docker-compose-tika-vision.yml&quot; target=&quot;_blank&quot;&gt;see here&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Enriching Academic PDF Parsing with Grobid REST (&lt;a href=&quot;https://github.com/apache/tika-docker/blob/master/docker-compose-tika-grobid.yml&quot; target=&quot;_blank&quot;&gt;see here&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;OCR of PDF or Images with Tesseract including a Custom  Configuration (&lt;a href=&quot;https://github.com/apache/tika-docker/blob/master/docker-compose-tika-customocr.yml&quot; target=&quot;_blank&quot;&gt;see here&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Named Entity Recognition (&lt;a href=&quot;https://github.com/apache/tika-docker/blob/master/docker-compose-tika-ner.yml&quot; target=&quot;_blank&quot;&gt;see here&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;using-the-examples&quot;&gt;Using the examples&lt;/h3&gt;

&lt;h5 id=&quot;install-docker-and-docker-compose&quot;&gt;Install Docker and Docker Compose&lt;/h5&gt;

&lt;p&gt;Follow the instructions for install &lt;em&gt;docker&lt;/em&gt; from &lt;a href=&quot;https://docs.docker.com/get-docker/&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Follow the instructions for installing &lt;em&gt;docker-compose&lt;/em&gt; from &lt;a href=&quot;https://docs.docker.com/compose/install/&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h5 id=&quot;clone-the-tika-docker&quot;&gt;Clone the tika-docker&lt;/h5&gt;

&lt;p&gt;Now fetch the docker-compose files and sample configuation from the &lt;em&gt;tika-docker&lt;/em&gt; project on GitHub:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git clone https://github.com/apache/tika-docker&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h5 id=&quot;run-docker-compose-for-example-you-want&quot;&gt;Run Docker Compose for Example You Want&lt;/h5&gt;

&lt;p&gt;First change into the tika-docker directory&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;tika-docker&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then you can execute docker-compose for the example you wish to try. For example, to try the Named Entity Recognition (NER) example you can:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;docker-compose &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; docker-compose-tika-ner.yml up &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can drop the -d if you want to stay attached to the containers.&lt;/p&gt;

&lt;p&gt;Then if you supplied a text file with some sample data to the &lt;em&gt;/meta&lt;/em&gt; endpoint:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOT&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt; &amp;gt;&amp;gt; test.txt
Hello world from the Apache Tika Team (dev@tika.apache.org).
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOT
&lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; test.txt http://localhost:9998/meta&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The RegEx Entity Recogniser configured in the &lt;a href=&quot;https://github.com/apache/tika-docker/tree/master/sample-configs/ner&quot; target=&quot;_blank&quot;&gt;NER sample configuration files&lt;/a&gt; would extract the email in the returned metadata:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&quot;X-Parsed-By&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;org.apache.tika.parser.CompositeParser&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;org.apache.tika.parser.ner.NamedEntityParser&quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;&quot;language&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;en&quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;&quot;NER_EMAIL&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;dev@tika.apache.org&quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;text/plain&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can then stop the running containers using&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;docker-compose &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; docker-compose-tika-ner.yml down&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;customising-the-examples&quot;&gt;Customising the examples&lt;/h3&gt;

&lt;p&gt;Each of the examples comes with associated set of configuration files in the &lt;a href=&quot;https://github.com/apache/tika-docker/tree/master/sample-configs&quot; target=&quot;_blank&quot;&gt;sample-configs&lt;/a&gt; directory.&lt;/p&gt;

&lt;p&gt;Each sample has an appropriately named subfolder, with the associated Tika Config XML file(s) and any other configuration resources, such as properties files specifying URLs or settings.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;├── customocr
│   ├── org
│   │   └── apache
│   │       └── tika
│   │           └── parser
│   │               └── ocr
│   │                   └── TesseractOCRConfig.properties
│   ├── tika-config-inline.xml
│   └── tika-config-rendered.xml
├── grobid
│   ├── org
│   │   └── apache
│   │       └── tika
│   │           └── parser
│   │               └── journal
│   │                   └── GrobidExtractor.properties
│   └── tika-config.xml
├── ner
│   ├── run_tika_server.sh
│   └── tika-config.xml
└── vision
    ├── inception-rest-caption.xml
    ├── inception-rest-video.xml
    └── inception-rest.xml&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h5 id=&quot;tika-config-xml&quot;&gt;Tika Config XML&lt;/h5&gt;

&lt;p&gt;All of the scenarios have &lt;a href=&quot;https://tika.apache.org/1.25/configuring.html&quot; target=&quot;_blank&quot;&gt;Tika Config XML&lt;/a&gt; files. These files configure the parsers or recognisers for the example.&lt;/p&gt;

&lt;p&gt;In some cases this file is named &lt;em&gt;tika-config.xml&lt;/em&gt; and is then loaded in the docker-compose file directly. In other examples, such as the Vision and OCR ones, the docker-compose file loads only one of the XML configurations as the default &lt;em&gt;tika-config.xml&lt;/em&gt; through a volume mount.&lt;/p&gt;

&lt;p&gt;For example, in the the Vision configuration for the Parsing and Captioning Video or Images with TensorFlow REST, you have a choice of three configurations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/apache/tika-docker/blob/master/sample-configs/vision/inception-rest-caption.xml&quot; target=&quot;_blank&quot;&gt;inception-rest-caption.xml&lt;/a&gt; - for image captioning&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/apache/tika-docker/blob/master/sample-configs/vision/inception-rest-video.xml&quot; target=&quot;_blank&quot;&gt;inception-rest-video.xml&lt;/a&gt; - for object recognition in videos&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/apache/tika-docker/blob/master/sample-configs/vision/inception-rest.xml&quot; target=&quot;_blank&quot;&gt;inception-rest.xml&lt;/a&gt; - for object recognition in images&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can chose which you want to use by leaving commented the appropriate configuration in the &lt;em&gt;docker-compose-tika-vision.yml&lt;/em&gt; file within the &lt;em&gt;volumes&lt;/em&gt; section:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#... snip ...&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Replace the below with the configuration you want to use, or with your own custom one &lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# -  ./sample-configs/vision/inception-rest.xml:/tika-config.xml&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# -  ./sample-configs/vision/inception-rest-video.xml:/tika-config.xml&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;./sample-configs/vision/inception-rest-caption.xml:/tika-config.xml&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;#... snip ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can find more on ObjectRecognition and the TensorFlow in Apache Tika Server from my previous blog post &lt;a href=&quot;/technology/opensource/apache-tika-and-objectrecognitionparser-tensorflow-rest.html&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;want-more&quot;&gt;Want more?&lt;/h2&gt;

&lt;p&gt;I plan to write most specific blog posts, similar to the Tensorflow REST one, on each of these example scenarios. So please subscribe to the &lt;a href=&quot;/feed.xml&quot; target=&quot;_blank&quot;&gt;RSS feed&lt;/a&gt; for this blog if you are interested.&lt;/p&gt;

&lt;p&gt;If you would like to see other examples like this, either let me know directly on GitHub or Twitter, or message on the Apache Tika Users or Developer &lt;a href=&quot;https://tika.apache.org/mail-lists.html&quot; target=&quot;_blank&quot;&gt;mailing lists&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Mon, 28 Dec 2020 08:00:00 +0000</pubDate>
        <link>https://meikle.io/technology/opensource/apache-tika-docker-examples.html</link>
        <guid isPermaLink="true">https://meikle.io/technology/opensource/apache-tika-docker-examples.html</guid>
        
        <category>apache</category>
        
        <category>tika</category>
        
        <category>examples</category>
        
        
        <category>technology</category>
        
        <category>opensource</category>
        
      </item>
    
      <item>
        <title>Apache Tika and the ObjectRecognitionParser for Object Recognition and Captioning Using TensorFlow REST.</title>
        <description>&lt;figure class=&quot;aligncenter&quot;&gt;
    &lt;img alt=&quot;people looking at a laptop screen&quot; src=&quot;/assets/img/john-schnobrich-2FPjlAyMQTA-unsplash.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;i&gt;&lt;span&gt;Photo by &lt;a href=&quot;https://unsplash.com/@johnschno?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;John Schnobrich&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/tech?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;One of the coolest new features added to &lt;a href=&quot;https://tika.apache.org&quot;&gt;Apache Tika&lt;/a&gt; in the past few years has been the addition of Parsers that leverage Deep Learning to perform object recognition and captioning.&lt;/p&gt;

&lt;p&gt;Contributed by Chris Mattmann and Thejan Wijesinghe, through their work with &lt;a href=&quot;https://github.com/USCDataScience/tika-dockers&quot;&gt;USC Data Science&lt;/a&gt;, you can configure Apache Tika to call of to predefined models and get deep learning equivalent of ‘Hello World’ - tagging dog or cat pictures!&lt;/p&gt;

&lt;p&gt;So let’s try it out.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;apache-tika-and-the-objectrecognitionparser&quot;&gt;Apache Tika and the ObjectRecognitionParser&lt;/h2&gt;

&lt;h3 id=&quot;what-is-the-objectrecognitionparser&quot;&gt;What is the ObjectRecognitionParser?&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;ObjectRecognitionParser&lt;/em&gt; is a Parser that can be configured to recognise objects within content and annotate the metadata with information on the objects it has recognised.&lt;/p&gt;

&lt;p&gt;Internally, the recognised objects are returned in a &lt;em&gt;RecognisedObject&lt;/em&gt; for generic objects or it’s &lt;em&gt;CaptionObject&lt;/em&gt; sub-class for captioning:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;RecognisedObject&lt;/em&gt; instances contain an ID, Label, Label Language and Confidence Score.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;CaptionObject&lt;/em&gt; instances contain an ID, Caption Sentence, Caption Language and Confidence Score.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both types are placed in the metadata collection during parsing.&lt;/p&gt;

&lt;p&gt;The type of recognition to be performed needs to be defined within Apache Tika’s &lt;em&gt;tika-config.xml&lt;/em&gt; through the configuration of &lt;em&gt;ObjectRecogniser&lt;/em&gt; instances to be used by the parser.&lt;/p&gt;

&lt;h3 id=&quot;available-object-recognisers&quot;&gt;Available Object Recognisers&lt;/h3&gt;

&lt;p&gt;There are a number of &lt;em&gt;ObjectRecogniser&lt;/em&gt; implementations in Apache Tika, including offline recognisers that need Deep Learning tools installed on the local machine (e.g. DL4J or Tensorflow) as well as online recognisers that make REST call to services.&lt;/p&gt;

&lt;p&gt;For now we are going to focus on the online recognisers, specifically ones that use Tensorflow REST APIs runnable in Docker from the &lt;a href=&quot;https://github.com/USCDataScience/tika-dockers&quot;&gt;USC Data Science&lt;/a&gt; team.&lt;/p&gt;

&lt;p&gt;These are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;TensorflowRESTRecogniser - which uses a custom REST API around Tensorflow to perform recognition on images&lt;/li&gt;
  &lt;li&gt;TensorflowRESTVideoRecogniser - which uses a custom REST API around Tensorflow to perform recognition on videos&lt;/li&gt;
  &lt;li&gt;TensorflowRESTCaptioner - which uses a custom REST API around Tensorflow to perform image captioning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These instances us an implementation based on the paper &lt;a href=&quot;https://arxiv.org/abs/1411.4555&quot;&gt;“Show and Tell: A Neural Image Caption Generator”&lt;/a&gt; for captioning images, and the &lt;a href=&quot;https://arxiv.org/abs/1602.07261&quot;&gt;Inception-V4&lt;/a&gt; model from Tensorflow for recognition in video and images.&lt;/p&gt;

&lt;p&gt;I’ll come back to the offline ones in another post.&lt;/p&gt;

&lt;h2 id=&quot;lets-try-it-out-on-tika-server&quot;&gt;Let’s try it out on Tika Server&lt;/h2&gt;

&lt;h3 id=&quot;get-the-docker-images&quot;&gt;Get the Docker Images&lt;/h3&gt;

&lt;p&gt;To make it easier to get up and running we’ll use Apache Tika Docker and the helper &lt;em&gt;docker-compose&lt;/em&gt; file.&lt;/p&gt;

&lt;p&gt;First, get the &lt;em&gt;tika-docker&lt;/em&gt; project from GitHub:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git clone https://github.com/apache/tika-docker&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In here is a file called &lt;em&gt;docker-compose-tika-vision.yml&lt;/em&gt; which contains everything you need.&lt;/p&gt;

&lt;p&gt;To make it easier we’ll create a symlink to allow us to execute &lt;em&gt;docker-compose&lt;/em&gt; without specifying the file each time:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; docker-compose-tika-vision.yml docker-compose.yml&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;configure-our-instance&quot;&gt;Configure our instance&lt;/h3&gt;

&lt;p&gt;Like most things is Apache Tika, the &lt;em&gt;ObjectRecogniser&lt;/em&gt; can be configured using the &lt;em&gt;tika-config.xml&lt;/em&gt; file format.&lt;/p&gt;

&lt;p&gt;To make things easier, there are three sample configuration to choose from to get your started:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;sample-configs/inception-rest.xml - for image recognition&lt;/li&gt;
  &lt;li&gt;sample-configs/inception-rest-caption.xml - for image captioning&lt;/li&gt;
  &lt;li&gt;sample-configs/inception-rest-video.xml - for video recognition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can do this by leaving only the configuration file entry you wish to use uncommented (or present) in the &lt;em&gt;volumes&lt;/em&gt; section of the &lt;em&gt;docker-compose&lt;/em&gt; file.&lt;/p&gt;

&lt;p&gt;For example, to use image captioning you can leave the following set:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;volumes:
 - ./sample-configs/inception-rest-caption.xml:/tika-config.xml&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;run-tika-server--inception-services&quot;&gt;Run Tika Server + Inception Services&lt;/h3&gt;

&lt;p&gt;With the above configuration set in the &lt;em&gt;docker-compose.yml&lt;/em&gt; file, you can now load up the containers:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;docker-compose up&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Apache Tika Server will keep trying to reload until it can detect the configured Inception Service instance. If so want to avoid this, you can start the Inception Service first and then Tika.&lt;/p&gt;

&lt;p&gt;Once they are loaded, you can now send some files to it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;wget https://upload.wikimedia.org/wikipedia/commons/f/f6/Working_Dogs%2C_Handlers_Share_Special_Bond_DVIDS124942.jpg &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; test.jpg
curl &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; test.jpg htp://localhost:9998/meta&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This should then give you suggested captions as part of the metadata collection parsed:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&quot;org.apache.tika.parser.recognition.object.rec.impl&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;org.apache.tika.parser.captioning.tf.TensorflowRESTCaptioner&quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;&quot;X-Parsed-By&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;org.apache.tika.parser.CompositeParser&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;org.apache.tika.parser.recognition.ObjectRecognitionParser&quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;&quot;language&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;en&quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;&quot;CAPTION&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;a man standing next to a dog on a leash . (0.00022)&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;a man standing next to a dog on a bench . (0.00017)&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;a man and a dog sitting on a bench . (0.00011)&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;a man standing next to a dog in a park . (0.00007)&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;a man and a dog sitting on a bench (0.00006)&quot;&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;image/jpeg&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;how-about-the-tika-app&quot;&gt;How about the Tika App?&lt;/h2&gt;
&lt;p&gt;You can also re-use the Inception Services from the &lt;em&gt;docker-compose.yml&lt;/em&gt; file for the Apache Tika app interactively.&lt;/p&gt;

&lt;p&gt;To do the captioning, you can just start the inception service you want - in this case &lt;em&gt;inception-caption&lt;/em&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;docker-compose up inception-caption &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can then create a custom &lt;em&gt;tika-config.xml&lt;/em&gt; and setting the appropriate &lt;em&gt;apiBaseUri&lt;/em&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;EOT &amp;gt;&amp;gt; tika-config.xml
&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;parsers&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;parser&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;org.apache.tika.parser.recognition.ObjectRecognitionParser&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;mime&amp;gt;&lt;/span&gt;image/jpeg&lt;span class=&quot;nt&quot;&gt;&amp;lt;/mime&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;mime&amp;gt;&lt;/span&gt;image/png&lt;span class=&quot;nt&quot;&gt;&amp;lt;/mime&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;mime&amp;gt;&lt;/span&gt;image/gif&lt;span class=&quot;nt&quot;&gt;&amp;lt;/mime&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;params&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;param&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;apiBaseUri&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;uri&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;http://localhost:8765/inception/v3&lt;span class=&quot;nt&quot;&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;param&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;captions&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;int&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;5&lt;span class=&quot;nt&quot;&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;param&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;maxCaptionLength&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;int&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;15&lt;span class=&quot;nt&quot;&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;param&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;class&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;org.apache.tika.parser.captioning.tf.TensorflowRESTCaptioner&lt;span class=&quot;nt&quot;&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;/params&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/parser&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/parsers&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;
EOT&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It’s worth noting in the sample configuration the &lt;em&gt;apiBaseUri&lt;/em&gt; uses the Docker Compose service name and internal port. For running outside, you’ll need to use the external facing port mapping and IP/Hostname of the machine it is running on.&lt;/p&gt;

&lt;p&gt;Then you can run the Apache Tika App JAR using your custom configuration. For example, to launch it in GUI mode you could use:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;java &lt;span class=&quot;nt&quot;&gt;-jar&lt;/span&gt; tika-app-1.25.jar &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;tika-config.xml &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;
&lt;p&gt;These REST based Tensorflow models are great examples of how Deep Learning can be used to augment the logic approach of Apache Tika for content parsing or detection.&lt;/p&gt;

&lt;p&gt;If you want to try adding basic tagging or captioning to your search or asset pipelines, these models could provide a start, or the REST API implementation provide inspiration for hosting your own Tensorflow models.&lt;/p&gt;

&lt;p&gt;It is an area that will continue to expand in the project and provides another API extension point where you can build your own &lt;em&gt;ObjectRecogniser&lt;/em&gt; implementations. Happy Parsing!&lt;/p&gt;
</description>
        <pubDate>Tue, 01 Dec 2020 08:00:00 +0000</pubDate>
        <link>https://meikle.io/technology/opensource/apache-tika-and-objectrecognitionparser-tensorflow-rest.html</link>
        <guid isPermaLink="true">https://meikle.io/technology/opensource/apache-tika-and-objectrecognitionparser-tensorflow-rest.html</guid>
        
        <category>apache</category>
        
        <category>tika</category>
        
        <category>tensorflow</category>
        
        
        <category>technology</category>
        
        <category>opensource</category>
        
      </item>
    
      <item>
        <title>HP Probook Touchpad Slow After Supend Ubuntu 19.04</title>
        <description>&lt;figure class=&quot;aligncenter&quot;&gt;
    &lt;img src=&quot;/assets/img/touchpad.jpg&quot; /&gt;
    &lt;figcaption&gt;Photo of a Laptop Touchpad&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Having got used to my replacement laptop, I’ve decided to keep using it, but there was one thing annoying me - the trackpad!&lt;/p&gt;

&lt;p&gt;The trackpad is definately not the same quality as the MacBook Pro I was used to, but I could cope as the main features are there. However, I often move around a lot going from meeting to meeting, making use of the sleep/suspend capability.&lt;/p&gt;

&lt;p&gt;That was when the trouble started…&lt;/p&gt;

&lt;!--more--&gt;

&lt;h1 id=&quot;sluggish-touch&quot;&gt;Sluggish Touch&lt;/h1&gt;

&lt;p&gt;Upon waking from suspend, the touchpad was sluggish and jumping all over the place, rendering the machine unusable without a mouse!&lt;/p&gt;

&lt;p&gt;The best way it seemed to get the touchpad to behave was to add post suspend script using &lt;em&gt;systemd&lt;/em&gt; to reload the driver. A little hacky but effective!&lt;/p&gt;

&lt;h1 id=&quot;systemd-and-suspendhibernation-hooks&quot;&gt;Systemd and Suspend/Hibernation Hooks&lt;/h1&gt;

&lt;p&gt;It is really easy to perform an action either before or after you suspend, with systemd providing a nice script based hook within its &lt;em&gt;systemd-suspend.service&lt;/em&gt; system service.&lt;/p&gt;

&lt;p&gt;To use this, all you need to do is put an executable script under /usr/lib/systemd/system-sleep/ that checks whether the first argument is ‘pre’ for before the system suspends, or ‘post’ for after the system wakes. The script can have any name.&lt;/p&gt;

&lt;p&gt;You can see more information in it’s man page:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;man systemd-suspend.service&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;the-script&quot;&gt;The Script&lt;/h1&gt;

&lt;p&gt;To sort this once and for all on the HP ProBook I wrote the following into a file called &lt;em&gt;/lib/systemd/system-sleep/touchpad-reload&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/bin/sh
case $1 in
  post)
    /sbin/rmmod i2c_hid &amp;amp;&amp;amp; /sbin/modprobe i2c_hid
  ;;
esac

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And now the touchpad is as happy post-suspend as it is on a fresh restart. Happy days!&lt;/p&gt;
</description>
        <pubDate>Fri, 06 Dec 2019 06:00:00 +0000</pubDate>
        <link>https://meikle.io/technology/hp-probook-touchpad-slow-after-suspend-ubuntu.html</link>
        <guid isPermaLink="true">https://meikle.io/technology/hp-probook-touchpad-slow-after-suspend-ubuntu.html</guid>
        
        <category>technology</category>
        
        <category>hp-probook</category>
        
        <category>touchpad</category>
        
        
        <category>technology</category>
        
      </item>
    
      <item>
        <title>Cisco Meraki Client VPN on Ubuntu 19.04/19.10/20.04</title>
        <description>&lt;figure class=&quot;aligncenter&quot;&gt;
    &lt;img src=&quot;/assets/img/cisco-meraki.png&quot; /&gt;
    &lt;figcaption&gt;Photo of Meraki MX84 Meraki Firewall from Cisco Meraki website&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;With my beloved, and worn, day to day laptop having to go in for repair, I had to setup a temporary laptop to work on for a few weeks.&lt;/p&gt;

&lt;p&gt;At work we use Cisco Meraki devices in many places, including the edge of network for our various offices. Whilst their main use is to form a mesh network around our offices and server infrastructure, we also use them to enable a lightweight Client VPN solution.&lt;/p&gt;

&lt;p&gt;The Cisco Meraki Client VPN option provides a L2TP/IPsec based VPN using either its own internal user store, an LDAP Directory, Microsoft Active Directory, or a Radius server to authenticate users.&lt;/p&gt;

&lt;p&gt;Cisco Meraki provide great instructions for Windows, Mac and mobile devices, but really old instructions for Linux. Therefore, I am posting this as much to remind me the next time I need to set it up as to help others.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h1 id=&quot;install-l2tp-plugins-for-network-manager&quot;&gt;Install L2TP Plugins for Network Manager&lt;/h1&gt;

&lt;p&gt;By default, support for L2TP VPNs is not installed for Network Manager, so we need to install them:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo apt-get install network-manager-l2tp
sudo apt-get install network-manager-l2tp-gnome

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;disable-system-xl2tpd&quot;&gt;Disable System xl2tpd&lt;/h1&gt;

&lt;p&gt;Network Manager spawns and manages its own instance of &lt;em&gt;xl2tpd&lt;/em&gt; so if there is a system instance still running it will not be able to use UDP port 1701, and will instead use an ephemeral port (i.e. random high port).&lt;/p&gt;

&lt;p&gt;To stop this from happening, we need to stop the deamon and disabling it from starting again:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo systemctl stop xl2tpd
sudo systemctl disable xl2tpd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;setup-your-vpn-connection&quot;&gt;Setup Your VPN Connection&lt;/h1&gt;

&lt;p&gt;Now you are ready to add your VPN connection. Having taken the steps above, we’ve Gnome Network Manager settings panel now includes the option to add L2TP VPN connections:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/nm-manager-screenshot-1.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The main settings we need to customise to work with Cisco Meraki Client VPN are on the &lt;em&gt;Identity&lt;/em&gt; tab.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/nm-identity-tab.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We can give our VPN a name, set the VPN gateway, and add our user credentials (with optional NT Domain depending whether Active Directory is used as the authentication scheme).&lt;/p&gt;

&lt;p&gt;We now need to set our &lt;em&gt;IPsec&lt;/em&gt; and &lt;em&gt;PPP&lt;/em&gt; settings.&lt;/p&gt;

&lt;h3 id=&quot;ipsec-settings&quot;&gt;IPsec Settings&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/nm-l2tp-ipsec-settings.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;IPsec Settings&lt;/em&gt; we need to tick the &lt;em&gt;Enable IPsec tunnel to L2TP host&lt;/em&gt; checkbox , expand the &lt;em&gt;Advanced&lt;/em&gt; settings, and then add three things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Pre-shared Key - adding the key provided by your network administrator&lt;/li&gt;
  &lt;li&gt;Phase1 Algorithm - use the following &lt;em&gt;3des-sha1-modp1024&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Phase2 Algorithm - use the following &lt;em&gt;3des-sha1&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click &lt;em&gt;OK&lt;/em&gt; to set this on the connection.&lt;/p&gt;

&lt;h3 id=&quot;ppp-settings&quot;&gt;PPP Settings&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/nm-l2tp-ppp-settings.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;PPP Settings&lt;/em&gt; we need to make sure &lt;em&gt;PPP&lt;/em&gt; is the only Authentication mechanism selected.&lt;/p&gt;

&lt;p&gt;The other defaults should be OK, however I’ve included a screenshot to confirm against above.&lt;/p&gt;

&lt;p&gt;Click &lt;em&gt;OK&lt;/em&gt; to set this on the connection.&lt;/p&gt;

&lt;h1 id=&quot;use-your-vpn-connection&quot;&gt;Use Your VPN Connection&lt;/h1&gt;

&lt;p&gt;The VPN should now be available in the Gnome Settings panel:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/nm-vpn-settings.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;and in the main Gnome Menu for quick connect/disconnect&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/vpn-gnome-settings-menu.png&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 02 Aug 2019 06:00:00 +0100</pubDate>
        <link>https://meikle.io/technology/cisco-meraki-client-vpn-on-ubuntu-1904.html</link>
        <guid isPermaLink="true">https://meikle.io/technology/cisco-meraki-client-vpn-on-ubuntu-1904.html</guid>
        
        <category>technology</category>
        
        <category>meraki</category>
        
        <category>vpn</category>
        
        
        <category>technology</category>
        
      </item>
    
      <item>
        <title>Hello world</title>
        <description>&lt;figure class=&quot;aligncenter&quot;&gt;
    &lt;img src=&quot;/assets/img/journey.jpg&quot; /&gt;
&lt;/figure&gt;

&lt;p&gt;Hello world! Please bear with me, I am just getting setup.&lt;/p&gt;
</description>
        <pubDate>Sun, 06 Jan 2019 08:00:00 +0000</pubDate>
        <link>https://meikle.io/personal/helloworld.html</link>
        <guid isPermaLink="true">https://meikle.io/personal/helloworld.html</guid>
        
        <category>personal</category>
        
        
        <category>personal</category>
        
      </item>
    
  </channel>
</rss>
