<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title></title>
  <subtitle></subtitle>
  <id>https://www.endpointdev.com/blog/tags/pdf/</id>
  <link href="https://www.endpointdev.com/blog/tags/pdf/"/>
  <link href="https://www.endpointdev.com/blog/tags/pdf/" rel="self"/>
  <updated>2022-01-02T00:00:00+00:00</updated>
  <author>
    <name>End Point Dev</name>
  </author>
  
    <entry>
      <title>Generate PDF with Chrome, Puppeteer, and Serverless Stack</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2022/01/generate-pdf-serverless-stack-chrome-puppeteer/"/>
      <id>https://www.endpointdev.com/blog/2022/01/generate-pdf-serverless-stack-chrome-puppeteer/</id>
      <published>2022-01-02T00:00:00+00:00</published>
      <author>
        <name>Afif Sohaili</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2022/01/generate-pdf-serverless-stack-chrome-puppeteer/banner.jpg&#34; alt=&#34;Cloud Computing and Serverless&#34;&gt;&lt;/p&gt;
&lt;!-- Image from Pixabay, Pixabay license: https://pixabay.com/illustrations/cloud-network-website-computer-6515064/ --&gt;
&lt;p&gt;Function as a Service (FaaS) solutions are becoming more and more mainstream today. The FaaS model allows developers to not have to worry about managing infrastructure and instead focus on writing the application logic. In the FaaS model, developers write individual functions that run specific tasks that are deployed together on a FaaS platform, including but not limited to Amazon Web Services (AWS), Azure, and Google Cloud Platform (GCP).&lt;/p&gt;
&lt;p&gt;These functions don&amp;rsquo;t always run like a traditional application server does, waiting for a request. Instead, these FaaS platforms only spin up instances of these functions whenever there is traffic and will shut them back down once there are no more requests after a given period of time. This helps make FaaS a really cheap platform while traffic is low. It is a good approach for on-demand tasks that are part of the application but not necessarily the most common path in a customer&amp;rsquo;s everyday journey within the application.&lt;/p&gt;
&lt;h3 id=&#34;the-tools&#34;&gt;The tools&lt;/h3&gt;
&lt;p&gt;In this tutorial, we&amp;rsquo;re going to be looking at implementing PDF download with Chrome, Puppeteer, and Serverless Stack, but first, let&amp;rsquo;s have a brief introduction of the tools that we are going to be using.&lt;/p&gt;
&lt;h4 id=&#34;1-serverless-stack&#34;&gt;1. Serverless Stack&lt;/h4&gt;
&lt;p&gt;Serverless Stack is a framework for building full-stack serverless apps. The bigger player in this space is the Serverless framework. Serverless Stack is giving the Serverless framework (yes, I know, it can be very confusing at times) a challenge to the throne. The latter has been around for many years now and has been the authority for building serverless apps. There are pros and cons to both of them.&lt;/p&gt;
&lt;p&gt;Serverless Stack&amp;rsquo;s biggest advantage is the live Lambda debugging, a faster development process and overall better development experience. With the Serverless framework, developers have to either constantly deploy to the cloud to test any change, or spend some time setting up &lt;code&gt;serverless-offline&lt;/code&gt; for simulated Lambda and API gateway environments on their local machines.&lt;/p&gt;
&lt;p&gt;But with the Serverless framework, developers are not tied to using a specific platform, as it can be used to deploy functions on AWS, Azure, and Google Cloud Platform. Serverless Stack, on the other hand, only allows deploying to AWS since its internals are built on top of AWS CDK.&lt;/p&gt;
&lt;h4 id=&#34;2-chrome-and-puppeteer&#34;&gt;2. Chrome and Puppeteer&lt;/h4&gt;
&lt;p&gt;Chrome will be used in this tutorial as a headless browser, controlled using Puppeteer. Puppeteer is a Node.js package that provides an API to make Chrome or Chromium navigate to a specific URL, take screenshots, click buttons, type in input fields, as well as take PDF screenshots. Note that the PDF screenshot feature is specific to Chrome and not Chromium, so make sure to double check that you are using the right browser.&lt;/p&gt;
&lt;h3 id=&#34;implementing-pdf-screenshot-and-download-with-serverless-stack-chrome-and-puppeteer&#34;&gt;Implementing PDF screenshot and download with Serverless Stack, Chrome, and Puppeteer&lt;/h3&gt;
&lt;p&gt;Now, let&amp;rsquo;s get to the meat of this tutorial. We are going to implement PDF generation with Chrome and Puppeteer, deployed on AWS Lambda through Serverless Stack. Here is what we will do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use Puppeteer in Chrome to navigate to a receipt page that we implemented.&lt;/li&gt;
&lt;li&gt;Instruct Chrome to take a PDF screenshot of the page.&lt;/li&gt;
&lt;li&gt;Stream the PDF file back to the user.&lt;/li&gt;
&lt;li&gt;Deploy this implementation on AWS Lambda using Serverless Stack and demonstrate the development experience throughout.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;PDF generation is a great use case for FaaS. It represents something that doesn&amp;rsquo;t happen very often and is triggered on demand by the user. Instead of letting our monolith application handle that intermittent traffic, we can delegate the task to FaaS in the cloud which will do this job without worrying us about scaling the infrastructure to cater to this particular use case. Then our application can just focus on handling the regular web traffic for general use.&lt;/p&gt;
&lt;h4 id=&#34;prerequisite-sample-receipt-pages&#34;&gt;Prerequisite: Sample receipt pages&lt;/h4&gt;
&lt;p&gt;First, let&amp;rsquo;s create some demo pages for PDF screenshots. I&amp;rsquo;m not going to go in-depth on these since it&amp;rsquo;s not the topic of the day. I have deployed these simple HTML pages that are styled like receipts on this Surge instance &lt;a href=&#34;https://unwieldy-key.surge.sh/&#34;&gt;here&lt;/a&gt;. You can find the code on GitHub &lt;a href=&#34;https://github.com/afifsohaili-ep/receipt-demos&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;getting-started&#34;&gt;Getting started&lt;/h4&gt;
&lt;p&gt;Let&amp;rsquo;s generate a new Serverless Stack project.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ npx create-serverless-stack@latest pdf-generator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; pdf-generator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ npm install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Congratulations, we have just created a new project with Serverless Stack! Here we get a basic template of a working Serverless Stack app. You can go &lt;a href=&#34;https://docs.serverless-stack.com/installation&#34;&gt;here&lt;/a&gt; for more information on how to get started with Serverless Stack.&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s look at the files we get from bootstrapping the project and customize them wherever we see fit.&lt;/p&gt;
&lt;h5 id=&#34;1-sstjson&#34;&gt;1. sst.json&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pdf-generator&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;region&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;us-east-1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;stacks/index.js&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This file is the entry point to the Serverless Stack app, and here we can define the region of choice, the name of the app, and the main file that Serverless Stack will use.&lt;/p&gt;
&lt;h5 id=&#34;2-stacksindexjs&#34;&gt;2. stacks/index.js&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; // stacks/index.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; app.setDefaultFunctionProps({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   runtime: &amp;#34;nodejs12.x&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-new MyStack(app, &amp;#34;my-stack&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+new MyStack(app, &amp;#34;pdf-generator&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;stacks/index.js&lt;/code&gt; is the main file declared in &lt;code&gt;sst.json&lt;/code&gt;. When building the project, Serverless Stack will use this file as an entry point to our application. This file is pretty simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It configures the Lambda functions to use the Node.js 12.x runtime.&lt;/li&gt;
&lt;li&gt;It registers a stack called &lt;code&gt;my-stack&lt;/code&gt;. This is the name of the CloudFormation stack on AWS. We definitely want to give it a better name than &lt;code&gt;my-stack&lt;/code&gt; here, so let&amp;rsquo;s rename that to &lt;code&gt;pdf-generator&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id=&#34;3-stacksmystackjs&#34;&gt;3. stacks/MyStack.js&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; * as sst from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;@serverless-stack/resources&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; MyStack &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;extends&lt;/span&gt; sst.Stack {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  constructor(scope, id, props) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;super&lt;/span&gt;(scope, id, props);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Create a HTTP API
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; api = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; sst.Api(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Api&amp;#34;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      routes: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;GET /&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;src/lambda.handler&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Show the endpoint in the output
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;.addOutputs({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ApiEndpoint&amp;#34;&lt;/span&gt;: api.url,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;MyStack.js&lt;/code&gt; is where we declare the resources we need inside a given CloudFormation stack. This can be anything from a cluster of Lambda functions, API Gateway endpoints, DynamoDB tables, S3 buckets, etc. The full list of resources that we can create with Serverless Stack is listed &lt;a href=&#34;https://docs.serverless-stack.com/constructs/Api&#34;&gt;here in the documentation&lt;/a&gt;. For our project we just need one API endpoint with API gateway, so what we are provided with here is already sufficient.&lt;/p&gt;
&lt;h4 id=&#34;deploying-the-project&#34;&gt;Deploying the project&lt;/h4&gt;
&lt;p&gt;Now, we can try to deploy this project to AWS. Ensure that the AWS Access Key ID and AWS Secret Access Key are set in the development environment, and then run &lt;code&gt;npx sst start&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# export AWS credentials&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;=&amp;lt;access key id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;=&amp;lt;secret access key&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# or if the credentials are set in ~/.aws/credentials&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;AWS_PROFILE&lt;/span&gt;=&amp;lt;AWS profile name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# Start the app in development mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npx sst start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After a few minutes, we will have the Cloudformation stack deployed on our AWS account. Keep in mind that the first deployment will take a bit longer than subsequent deployments. When the deployment is done, we should be able to see that it is watching for file changes from our local machine.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;threadlightly-pdf-generator-pdf-generator | CREATE_COMPLETE | AWS::ApiGatewayV2::Route | ApiRouteGET8AC7D3F8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;threadlightly-pdf-generator-pdf-generator | CREATE_COMPLETE | AWS::Lambda::Permission | ApiRouteGETthreadlightlypdfgeneratorpdfgeneratorApiRouteGET7230D6CDPermissionE4542537
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;threadlightly-pdf-generator-pdf-generator | CREATE_COMPLETE | AWS::CloudFormation::Stack | threadlightly-pdf-generator-pdf-generator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ✅  threadlightly-pdf-generator-pdf-generator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Stack threadlightly-pdf-generator-pdf-generator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Status: deployed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Outputs:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ApiEndpoint: https://&amp;lt;yourapigatewayurl&amp;gt;.execute-api.us-east-1.amazonaws.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==========================
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Starting Live Lambda Dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;==========================
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Transpiling Lambda code...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Debug session started. Listening for requests...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let&amp;rsquo;s head to the API URL given in the output and we should get a response back like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello, World! Your request was received at 30/Nov/2021:06:21:13 +0000.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;developing-with-serverless-stack&#34;&gt;Developing with Serverless Stack&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s try updating one of the files provided to see how we can test the changes we have made and will make.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; // stacks/MyStack.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; const api = new sst.Api(this, &amp;#34;Api&amp;#34;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   routes: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    &amp;#34;GET /&amp;#34;: &amp;#34;src/lambda.handler&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    &amp;#34;GET /downloads/receipt&amp;#34;: &amp;#34;src/lambda.handler&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;   },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; // stacks/index.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   runtime: &amp;#34;nodejs12.x&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-new MyStack(app, &amp;#34;my-stack&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+new MyStack(app, &amp;#34;pdf-generator&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here we did two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We updated the API endpoint to &lt;code&gt;GET /downloads/receipt&lt;/code&gt; instead of just &lt;code&gt;GET /&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We made the Lambda function return the URL given in the query string.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once we save these changes we should see Serverless Stack automatically reloading our code and since we changed the API endpoint path, Serverless Stack will need to make changes to our infrastructure (i.e. the API Gateway resources), and whenever it detects that it has to change the infrastructure of our application, it will immediately prompt us to redeploy.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Rebuilding code...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Rebuilding infrastructure...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Done building code
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Press ENTER to redeploy infrastructure&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once we hit ENTER, Serverless Stack will automatically update our infrastructure for us: delete our old endpoint, create a new endpoint on &lt;code&gt;GET /downloads/receipt&lt;/code&gt;, and hook up our &lt;code&gt;src/lambda.js&lt;/code&gt; file to handle that endpoint.&lt;/p&gt;
&lt;p&gt;When it&amp;rsquo;s ready, try hitting the API gateway URL again, but this time append &lt;code&gt;/downloads/receipt?url=https://google.com&lt;/code&gt; to it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// https://&amp;lt;yourapigatewayurl&amp;gt;.execute-api.us-east-1.amazonaws.com/downloads/receipt?url=https://google.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello! You&amp;#39;ve requested to print the receipt at page https://google.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Great, now we have learned how to make changes to our Serverless Stack application during development. Let&amp;rsquo;s go ahead and add Puppeteer and Chrome to our Lambda function.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; // stacks/MyStack.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; import * as sst from &amp;#34;@serverless-stack/resources&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+import { LayerVersion } from &amp;#34;@aws-cdk/aws-lambda&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+const layerArn = &amp;#34;arn:aws:lambda:us-east-1:764866452798:layer:chrome-aws-lambda:25&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; // Create a HTTP API
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; const api = new sst.Api(this, &amp;#34;Api&amp;#34;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   routes: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-     &amp;#34;GET /downloads/receipt&amp;#34;: &amp;#34;src/lambda.handler&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+     &amp;#34;GET /downloads/receipt&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+       function: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+         handler: &amp;#34;src/lambda.handler&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+         // Increase the timeout for generating screenshots
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+         timeout: 15,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+         // Load Chrome in a Layer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+         layers: [LayerVersion.fromLayerVersionArn(this, &amp;#34;Layer&amp;#34;, layerArn)],
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+         // Exclude bundling it in the Lambda function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+         bundle: { externalModules: [&amp;#34;chrome-aws-lambda&amp;#34;] },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+       }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+     },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;   },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, we are configuring our AWS Lambda function to use a Lambda layer that includes Chrome in our Lambda functions. You can think of these Lambda layers as being similar to NPM packages that you pull for extending your projects except that this is a 3rd party package for extending AWS Lambda functions instead.&lt;/p&gt;
&lt;p&gt;With this layer, your AWS Lambda function will boot with the Chrome binary already included. This layer is maintained &lt;a href=&#34;https://github.com/shelfio/chrome-aws-lambda-layer&#34;&gt;here&lt;/a&gt;. Make sure you&amp;rsquo;re using the ARN from the right region. In this tutorial, we are using &lt;code&gt;us-east-1&lt;/code&gt; per Serverless Stack&amp;rsquo;s default, so we are going to pick the ARN for &lt;code&gt;us-east-1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, let&amp;rsquo;s update our Lambda handler to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use Puppeteer to instruct Chrome to navigate to the URL passed in the parameter.&lt;/li&gt;
&lt;li&gt;Take a screenshot of the web page and save a PDF out of that. Puppeteer provides a handy &lt;code&gt;page.pdf&lt;/code&gt; API to do just that.&lt;/li&gt;
&lt;li&gt;Ultimately, stream that PDF file back to the user.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&amp;rsquo;s the code for that, with some comments to help you out:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+import chrome from &amp;#34;chrome-aws-lambda&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+const puppeteer = chrome.puppeteer;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; export async function handler(event) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-  return {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    statusCode: 200,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    headers: { &amp;#34;Content-Type&amp;#34;: &amp;#34;text/plain&amp;#34; },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    body: `Hello! You&amp;#39;ve requested to print the receipt at page ${event.queryStringParameters.url}`,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-  };
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  let browser
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  let response
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  try {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    const { url } = event.queryStringParameters;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    browser = await puppeteer.launch({
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      args: chrome.args,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      executablePath: await chrome.executablePath,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    const page = await browser.newPage();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    // Use A5 size at 150dpi
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    const width = 874
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    const height = 1240
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    await page.setViewport({ width, height });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    // Navigate to the url
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    await page.goto(url, { waitUntil: &amp;#39;networkidle2&amp;#39; });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    // Take the screenshot
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    await page.pdf({path: &amp;#39;receipt.pdf&amp;#39;, width: width + &amp;#34;px&amp;#34;, height: height + &amp;#34;px&amp;#34;, printBackground: true});
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    response = {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      statusCode: 200,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      body: JSON.stringify({message: &amp;#39;Screenshot taken&amp;#39;})
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    };
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  } catch(err) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    response = {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      statusCode: 500,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      body: JSON.stringify({message: `An error occured. ${err.message}`})
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  } finally {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    await browser &amp;amp;&amp;amp; browser.close()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  return response
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let&amp;rsquo;s also not forget to install Puppeteer and Chrome.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ npm install puppeteer puppeteer-core chrome-aws-lambda&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, give Serverless Stack some time to reload our new changes. Once we have the API endpoint ready to go, let&amp;rsquo;s head to the browser and hit our API endpoint, passing the URL to the sample receipt page that we did earlier as a query param.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// Visit https://&amp;lt;yourapigatewayurl&amp;gt;.execute-api.us-east-1.amazonaws.com/downloads/receipt?url=https://unwieldy-key.surge.sh/index.html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// Response:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&amp;#34;message&amp;#34;:&amp;#34;Screenshot taken&amp;#34;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Great! We are getting back a 200 status code and a message saying &amp;ldquo;Screenshot taken&amp;rdquo;. That means our code works and there were no exceptions. We&amp;rsquo;re halfway there.&lt;/p&gt;
&lt;p&gt;Now, if we check the project folder, we should now see a new file called &lt;code&gt;receipt.pdf&lt;/code&gt; there. This is the &lt;code&gt;receipt.pdf&lt;/code&gt; captured by Puppeteer. We can open this file and verify that this is the demo receipt page that I deployed earlier that we passed to the endpoint.&lt;/p&gt;
&lt;p&gt;We can also hit the API endpoint with the second sample receipt URL (i.e. &lt;code&gt;url=https://unwieldy-key.surge.sh/receipt-2.html&lt;/code&gt;) and we should see the &lt;code&gt;receipt.pdf&lt;/code&gt; file gets replaced with the receipt from the new URL.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2022/01/generate-pdf-serverless-stack-chrome-puppeteer/page-screenshot.png&#34; alt=&#34;receipt.pdf file that we get&#34;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that in a real-world application, the URL you would want to screenshot might need some form of authentication, so you are going to have to figure that out for your application. In this case the sample receipt page is accessible publicly, so we don&amp;rsquo;t run into this problem, but chances are your users&amp;rsquo; receipt page will not be accessible publicly like this.&lt;/p&gt;
&lt;p&gt;One way you could solve this is to create a special user account that has permission to visit these authenticated pages for this purpose. Then, prior to visiting the receipt page, you&amp;rsquo;d program Puppeteer to first log in as the special user and then head to the receipt page URL to be screenshot.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;However, we are only halfway there. We can see the &lt;code&gt;receipt.pdf&lt;/code&gt; file now only because the &lt;code&gt;receipt.pdf&lt;/code&gt; file was made available to us by Serverless Stack, which automatically downloads that file to our local machine in development mode. In a real AWS Lambda execution, the file will remain in the filesystem of that Lambda execution context instead, and the user will not see it.&lt;/p&gt;
&lt;p&gt;Hence we have to read and stream that file back to the user instead of returning a JSON message saying &amp;ldquo;Screenshot taken&amp;rdquo;. Getting a 200 status code is a great start, but that still does not give our users the actual PDF that they wanted, so let&amp;rsquo;s update our Lambda handler to do just that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; // src/lambda.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+import * as fs from &amp;#34;fs&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; // Take the screenshot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; await page.pdf({path: &amp;#39;receipt.pdf&amp;#39;, width: width + &amp;#34;px&amp;#34;, height: height + &amp;#34;px&amp;#34;, printBackground: true});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+const buffer = fs.readFileSync(&amp;#39;receipt.pdf&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; response = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   statusCode: 200,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-  body: JSON.stringify({message: &amp;#39;Screenshot taken&amp;#39;})
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  headers: {&amp;#39;Content-type&amp;#39; : &amp;#39;application/pdf&amp;#39;},
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  body: buffer.toString(&amp;#39;base64&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  isBase64Encoded : true,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The changes this time are pretty simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Import the &lt;code&gt;fs&lt;/code&gt; module from Node.js, which will give us access to &lt;code&gt;readFileSync&lt;/code&gt; API that can read files on the disk.&lt;/li&gt;
&lt;li&gt;Read the generated &lt;code&gt;receipt.pdf&lt;/code&gt; file as a Buffer.&lt;/li&gt;
&lt;li&gt;Return the file&amp;rsquo;s Buffer as a base64 string in the response body.&lt;/li&gt;
&lt;li&gt;Set the content-type to be &lt;code&gt;application/pdf&lt;/code&gt;. Setting the content-type appropriately will tell the browser what to do with the file. Some browsers will display the PDF in an in-browser PDF reader, while others will download the file.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&amp;rsquo;s it! Now let&amp;rsquo;s test the change. Hit the same URL again.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2022/01/generate-pdf-serverless-stack-chrome-puppeteer/pdf-file.png&#34; alt=&#34;The PDF returned in a response, rendered in a PDF viewer in Edge&#34;&gt;&lt;/p&gt;
&lt;p&gt;Bingo, the endpoint now returns the PDF to the user! Now we can integrate this endpoint with our main application to delegate these on-demand PDF generation to managed FaaS infrastructure.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;FaaS platforms are a really great way to offload intermittent and on-demand traffic from our main application. This ensures our application runs smoother and can serve our general customers better, while at the same time handling these on-demand tasks really well.&lt;/p&gt;
&lt;h5 id=&#34;caveats&#34;&gt;Caveats&lt;/h5&gt;
&lt;p&gt;Building a full-blown application on the stack is also possible, but in my personal experience, it comes with its own complexities and tradeoffs that may or may not be worth the engineering time.&lt;/p&gt;
&lt;p&gt;For example, databases are an issue with going full-blown development on FaaS. Because FaaS can scale indefinitely, the number of connections to the database is a limitation.&lt;/p&gt;
&lt;p&gt;You can switch to FaaS-friendly databases such as DynamoDB or FaunaDB, but these are NoSQL databases and require a different mindset in structuring the application data than the simpler relational databases and that can cost tremendous engineering time. Relational databases are easier to work with for most types of applications.&lt;/p&gt;
&lt;p&gt;Nonetheless, more and more tools are being developed to tackle these complexities, such as &lt;a href=&#34;https://planetscale.com/&#34;&gt;PlanetScale&lt;/a&gt; and &lt;a href=&#34;https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-2.how-it-works.html&#34;&gt;Serverless Aurora v2&lt;/a&gt; (still in preview). All in all, it is definitely a trend worth following closely.&lt;/p&gt;
&lt;h3 id=&#34;further-readings&#34;&gt;Further readings&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Full code on GitHub: &lt;a href=&#34;https://github.com/afifsohaili-ep/serverless-stack-pdf-generator&#34;&gt;https://github.com/afifsohaili-ep/serverless-stack-pdf-generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Code for the sample receipt pages: &lt;a href=&#34;https://github.com/afifsohaili-ep/receipt-demos&#34;&gt;https://github.com/afifsohaili-ep/receipt-demos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Serverless Stack: &lt;a href=&#34;https://serverless-stack.com/&#34;&gt;https://serverless-stack.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Serverless framework: &lt;a href=&#34;https://serverless.com/&#34;&gt;https://serverless.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.alldaydevops.com/blog/serverless-databases-the-good-the-bad-and-the-ugly&#34;&gt;Serverless Databases: The Good, the Bad, and the Ugly&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
    <entry>
      <title>Convenient Reporting with Jasper</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2020/04/convenient-reporting-with-jasper/"/>
      <id>https://www.endpointdev.com/blog/2020/04/convenient-reporting-with-jasper/</id>
      <published>2020-04-28T00:00:00+00:00</published>
      <author>
        <name>Árpád Lajos</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2020/04/convenient-reporting-with-jasper/symphony-of-stones.jpg&#34; alt=&#34;Basalt pillars&#34;&gt;&lt;/p&gt;
&lt;p&gt;Business Intelligence (BI) reporting is a huge problem space in custom software. There’s a wide range of business needs for looking at past and predictive behavior. Building a reporting tool can be a very cost effective way to get this data, especially compared to writing individual queries or manually generating reports.&lt;/p&gt;
&lt;p&gt;I’ve been working with Jasper in the Java project space and wanted to write about some research I’ve collected on the topic.&lt;/p&gt;
&lt;p&gt;JasperReports takes .jrxml files as input and outputs a .jasper report. Possible output targets include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Screen&lt;/li&gt;
&lt;li&gt;Printer&lt;/li&gt;
&lt;li&gt;PDF&lt;/li&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;Excel files&lt;/li&gt;
&lt;li&gt;RTF&lt;/li&gt;
&lt;li&gt;ODT&lt;/li&gt;
&lt;li&gt;CSV&lt;/li&gt;
&lt;li&gt;XML&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;jasper-history&#34;&gt;Jasper history&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;June 2001:&lt;/strong&gt; Teodor Danciu began working on JasperReports.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;September 2001:&lt;/strong&gt; Jasper was registered on SourceForge.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;November 2001:&lt;/strong&gt; JasperReports 0.1.5 was released.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2004:&lt;/strong&gt; Panscopic teamed up with Teodor Danciu, acquired ownership of the product and changed its name to &lt;a href=&#34;https://www.jaspersoft.com/&#34;&gt;Jaspersoft&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2005:&lt;/strong&gt; JasperReports 1.0 was released.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2007:&lt;/strong&gt; Brian Gentile became CEO of the company.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2014:&lt;/strong&gt; TIBCO acquired Jaspersoft for ~$185 million.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;best-reporting-tools&#34;&gt;Best reporting tools&lt;/h3&gt;
&lt;p&gt;Let’s compare some popular reporting tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JasperReports&lt;/strong&gt; is a free and open source Java-based reporting tool, which supports lots of possible outputs, as mentioned earlier. Generating reports can be difficult if you’re less technical. More technical aspects can be more difficult as well; embedding JasperReports into a project is not necessarily simple, but once it’s done, the tool will be reliable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Crystal Reports&lt;/strong&gt; supports many inputs, including Access, Excel, XML, ODBC, and JDBC. It also has good multi-language support. It’s easy to embed into a .NET project, but software updates are unstable. The process can be very slow and there is no control of data-level security. A trial version is offered, but if one wants to use it long-term, then the price is a one-time payment of $495 or more, for larger companies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Domo&lt;/strong&gt; is another a popular reporting tool. It provides a trial version, and a 5 user plan costs $5700/year*.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zoho analytics&lt;/strong&gt; is an easy-to-use BI reporting tool, priced between $22–$445, depending on the number of users and data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Host analytics&lt;/strong&gt; is a great tool for finance automation. Pricing not publicized.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tableau&lt;/strong&gt; is an excellent reporting tool, with a thriving community online, but its quote-based price is high.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pentaho&lt;/strong&gt; is a Java-based reporting tool, which provides data integration, online analytical processing and reporting, among other features. Pentaho offers a 30-day trial period. Contract pricing isn’t disclosed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, if you are writing software and already use Java, or using Java reporting is an option, JasperReports is a great choice. It supports a variety of outputs, is free to use, and open source.&lt;/p&gt;
&lt;h3 id=&#34;installing-jasperreports-server&#34;&gt;Installing JasperReports Server&lt;/h3&gt;
&lt;p&gt;To install JasperReports Server, you need a computer with a fully functional JRE (Java Runtime Environment). The server might be Tomcat or GlassFish. An RDBMS is also needed. since JasperReports has its own database, this could be PostgreSQL, Oracle, MySQL, DB2, or SQL Server. JasperReports prefers PostgreSQL and Tomcat, so these will be included with an automatic install. You may choose to use your existing Tomcat/PostgreSQL or have it install them as well.&lt;/p&gt;
&lt;p&gt;Manual installation is also possible, as described &lt;a href=&#34;https://community.jaspersoft.com/documentation/tibco-jasperreports-server-installation-guide/v630/installing-jasperreports-server&#34;&gt;here&lt;/a&gt;. At my first encounter with Jasper I installed Tomcat with the installer and used it for generating JasperReports, while the application I was working with was running WildFly (formerly JBoss), using a MySQL database. Needless to say, this was unnecessary, but I was not aware of that at the time. JasperServer can be configured to work with JBoss and MySQL as well.&lt;/p&gt;
&lt;p&gt;The core of JasperReports is the &lt;a href=&#34;https://community.jaspersoft.com/wiki/getting-started-jasperreports-library&#34;&gt;JasperReports Library&lt;/a&gt;, which was already integrated into the project I was working with and is integrated into JasperReports Server as well as into popular IDEs, like TIBCO Jaspersoft Studio or iReport Designer.&lt;/p&gt;
&lt;h3 id=&#34;database&#34;&gt;Database&lt;/h3&gt;
&lt;p&gt;JasperReports provides example databases for imaginary companies, like FoodMart:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/04/convenient-reporting-with-jasper/foodmart.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;As we can see these are normal tables, having a primary key and some other fields.&lt;/p&gt;
&lt;h3 id=&#34;jrxml&#34;&gt;.jrxml&lt;/h3&gt;
&lt;p&gt;jrxml, which stands for Jasper XML, contains report definitions in XML format. This type of file can be edited as code or visually to be compiled into .jasper files. &lt;a href=&#34;https://community.jaspersoft.com/wiki/jasperreports-library-samples&#34;&gt;The community&lt;/a&gt; provides samples that can be used and understood. Among them we can find a JFreeChart sample, which contains a jrxml file, a preview HTML and an actual PDF. The .jrxml file looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;!DOCTYPE jasperReport PUBLIC &amp;#34;-//JasperReports//DTD Report Design//EN&amp;#34; &amp;#34;http://jasperreports.sourceforge.net/dtds/jasperreport.dtd&amp;#34;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;jasperReport&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;JFreeChartReport&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pageWidth=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;595&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pageHeight=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;842&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;columnWidth=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;leftMargin=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;40&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rightMargin=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;40&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;topMargin=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;50&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;bottomMargin=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;50&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;scriptletClass=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;JFreeChartScriptlet&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;variable&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Chart&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;net.sf.jasperreports.engine.JRRenderable&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;calculation=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;System&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;band&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;742&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;line&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;graphicElement/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/line&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;staticText&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;30&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;textAlignment=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Center&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;font&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;size=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;22&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textElement&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;text&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[JFreeChart Sample]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/text&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/staticText&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;50&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;50&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;textAlignment=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Center&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;font&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;size=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;12&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textElement&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[&amp;#34;This sample uses JFreeChart Version 1.0.0-pre2\n&amp;#34; + &amp;#34;Written by David Gilbert (david.gilbert@object-refinery.com) and others.\n&amp;#34; + &amp;#34;(C)opyright 2000-2004, by Object Refinery Limited and Contributors.&amp;#34;]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;image&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;scaleImage=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Clip&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;hAlign=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Center&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;hyperlinkType=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Reference&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;110&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;300&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;graphicElement/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;imageExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;net.sf.jasperreports.engine.JRRenderable&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[$V{Chart}]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/imageExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;hyperlinkReferenceExpression&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[&amp;#34;http://www.jfree.org/jfreechart&amp;#34;]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/hyperlinkReferenceExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/image&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/band&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/jasperReport&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It starts with the xml tag, specifying that this file should be interpreted as XML. Then comes the DOCTYPE and finally the jasperReport node, which contains the actual report nodes. A &lt;a href=&#34;https://community.jaspersoft.com/wiki/using-report-variables&#34;&gt;variable&lt;/a&gt; is defined, called Chart, which is used later in the inner XML of the image node. A hyperlink is defined for the image. The preview for this report looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/04/convenient-reporting-with-jasper/preview.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Don’t worry about the broken images; this is just the preview, the actual result looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/04/convenient-reporting-with-jasper/piechart.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Nice, isn’t it?&lt;/p&gt;
&lt;h3 id=&#34;data-source&#34;&gt;Data source&lt;/h3&gt;
&lt;p&gt;It’s nice to generate reports, but in many cases the content is not fully known at programming time. It’s quite possible that we need to provide some input for the template. For this purpose, the interface of &lt;a href=&#34;http://jasperreports.sourceforge.net/api/net/sf/jasperreports/engine/JRDataSource.html&#34;&gt;JRDataSource&lt;/a&gt; was defined to be iterated with a &lt;code&gt;.next()&lt;/code&gt; method and is readable via the &lt;code&gt;.getFieldValue()&lt;/code&gt; method. To make sure that we can read fields, another interface, &lt;a href=&#34;http://jasperreports.sourceforge.net/api/net/sf/jasperreports/engine/JRField.html&#34;&gt;JRField&lt;/a&gt; was defined as well. We therefore will need to use implementations of these classes, possibly writing our own if the currently available implementations are not fulfilling our needs.&lt;/p&gt;
&lt;p&gt;Let’s consider a datasource sample, also taken from the &lt;a href=&#34;https://community.jaspersoft.com/wiki/jasperreports-library-samples&#34;&gt;community&lt;/a&gt;. It has this .jrxml template:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;!DOCTYPE jasperReport PUBLIC &amp;#34;-//JasperReports//DTD Report Design//EN&amp;#34; &amp;#34;http://jasperreports.sourceforge.net/dtds/jasperreport.dtd&amp;#34;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;jasperReport&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;DataSourceReport&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pageWidth=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;595&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pageHeight=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;842&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;columnWidth=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;leftMargin=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;40&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rightMargin=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;40&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;topMargin=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;50&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;bottomMargin=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;50&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;style&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial_Normal&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isDefault=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;fontName=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;fontSize=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;12&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isBold=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isItalic=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isUnderline=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isStrikeThrough=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pdfFontName=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Helvetica&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pdfEncoding=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Cp1252&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isPdfEmbedded=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;style&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial_Bold&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isDefault=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;fontName=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;fontSize=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;12&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isBold=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isItalic=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isUnderline=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isStrikeThrough=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pdfFontName=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Helvetica-Bold&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pdfEncoding=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Cp1252&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isPdfEmbedded=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;style&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial_Italic&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isDefault=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;fontName=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;fontSize=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;12&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isBold=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isItalic=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isUnderline=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isStrikeThrough=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pdfFontName=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Helvetica-Oblique&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;pdfEncoding=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Cp1252&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isPdfEmbedded=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;parameter&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ReportTitle&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;parameter&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;DataFile&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;field&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.Integer&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;field&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;field&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;street&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;field&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;the_city&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;fieldDescription&amp;gt;&lt;/span&gt;me.me.city&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/fieldDescription&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/field&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;variable&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;CityNumber&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.Integer&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;incrementType=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Group&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;incrementGroup=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;CityGroup&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;calculation=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Count&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;variableExpression&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[Boolean.TRUE]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/variableExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/variable&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;group&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;CityGroup&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;minHeightToStartNewPage=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;60&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;groupExpression&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[$F{the_city}]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/groupExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;groupHeader&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;band&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;20&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;evaluationTime=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Group&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;evaluationGroup=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;CityGroup&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;bookmarkLevel=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;mode=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Opaque&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;5&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;backcolor=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#c0c0c0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;style=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial_Bold&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;box&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;leftPadding=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;bottomBorder=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1Point&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[&amp;#34;  &amp;#34; + String.valueOf($V{CityNumber}) + &amp;#34;. &amp;#34; + String.valueOf($F{the_city})]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;anchorNameExpression&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[String.valueOf($F{the_city})]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/anchorNameExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/band&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/groupHeader&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;groupFooter&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;band&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;20&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;staticText&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;400&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;60&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;style=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial_Bold&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;textAlignment=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Right&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;text&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[Count :]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/text&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/staticText&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;460&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;30&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;style=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial_Bold&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;textAlignment=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Right&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.Integer&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[$V{CityGroup_COUNT}]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/band&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/groupFooter&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/group&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;band&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;70&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;line&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;graphicElement/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/line&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isBlankWhenNull=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;bookmarkLevel=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;30&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;style=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial_Normal&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;textAlignment=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Center&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;font&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;size=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;22&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textElement&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[$P{ReportTitle}]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;anchorNameExpression&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[&amp;#34;Title&amp;#34;]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/anchorNameExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isBlankWhenNull=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;40&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;20&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;style=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial_Normal&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;textAlignment=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Center&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;font&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;size=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;14&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textElement&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[$P{DataFile}]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/band&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;pageHeader&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;band&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;20&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;rectangle&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;5&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;forecolor=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#333333&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;backcolor=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#333333&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;graphicElement/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/rectangle&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;staticText&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;mode=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Opaque&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;5&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;55&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;forecolor=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#ffffff&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;backcolor=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#333333&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;style=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial_Bold&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;textAlignment=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Center&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;text&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[ID]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/text&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/staticText&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;staticText&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;mode=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Opaque&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;55&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;5&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;205&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;forecolor=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#ffffff&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;backcolor=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#333333&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;style=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial_Bold&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;text&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[Name]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/text&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/staticText&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;staticText&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;mode=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Opaque&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;260&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;5&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;255&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;forecolor=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#ffffff&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;backcolor=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#333333&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;style=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Arial_Bold&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;text&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[Street]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/text&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/staticText&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/band&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/pageHeader&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;detail&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;band&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;bookmarkLevel=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;50&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;box&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;leftBorder=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Thin&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;bottomBorder=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Thin&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;leftPadding=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rightPadding=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;textAlignment=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Right&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.Integer&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[$F{id}]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;anchorNameExpression&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[$F{name} + &amp;#34; (&amp;#34; + $F{id} + &amp;#34;)&amp;#34;]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/anchorNameExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isStretchWithOverflow=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;positionType=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Float&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;50&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;200&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;box&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;leftBorder=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Thin&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;bottomBorder=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Thin&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;leftPadding=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rightPadding=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[$F{name}]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;isStretchWithOverflow=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;positionType=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Float&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;250&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;265&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;box&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;leftBorder=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Thin&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;bottomBorder=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Thin&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rightBorder=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Thin&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;leftPadding=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rightPadding=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[$F{street}]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/band&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/detail&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;pageFooter&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;band&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;40&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;line&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;graphicElement/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/line&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;200&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;20&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;80&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;textAlignment=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Right&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[&amp;#34;Page &amp;#34; + String.valueOf($V{PAGE_NUMBER}) + &amp;#34; of&amp;#34;]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;evaluationTime=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Report&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;280&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;20&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;75&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[&amp;#34; &amp;#34; + String.valueOf($V{PAGE_NUMBER})]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/band&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/pageFooter&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;lastPageFooter&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;band&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;60&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;bookmarkLevel=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;textAlignment=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Center&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[&amp;#34;There were &amp;#34; +
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;          String.valueOf($V{REPORT_COUNT}) +
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;          &amp;#34; address records on this report.&amp;#34;]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;anchorNameExpression&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[&amp;#34;Summary&amp;#34;]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/anchorNameExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;line&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;30&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;515&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;graphicElement/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/line&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;200&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;40&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;80&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;textAlignment=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Right&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[&amp;#34;Page &amp;#34; + String.valueOf($V{PAGE_NUMBER}) + &amp;#34; of&amp;#34;]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textField&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;evaluationTime=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Report&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;reportElement&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;x=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;280&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;y=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;40&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;width=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;75&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;height=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;15&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textElement/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;textFieldExpression&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java.lang.String&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;&amp;lt;![CDATA[&amp;#34; &amp;#34; + String.valueOf($V{PAGE_NUMBER})]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textFieldExpression&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/textField&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/band&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/lastPageFooter&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/jasperReport&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As we can see, there are fields defined like &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;street&lt;/code&gt;, and &lt;code&gt;the_city&lt;/code&gt;. We also have a group called &lt;code&gt;CityGroup&lt;/code&gt;, so when the items from the data source are iterated through, their group is known via &lt;code&gt;the_city&lt;/code&gt;. It’s worth looking at how the paging works. The key is &lt;code&gt;evaluationTime&lt;/code&gt;, which is telling the engine to not evaluate a given element at iteration time, but rather when an event occurs. &lt;code&gt;evaluationTime=&amp;quot;Report&amp;quot;&lt;/code&gt; means that we need to evaluate the value when the &lt;em&gt;Report&lt;/em&gt; event occurs. At that time &lt;code&gt;$V{PAGE_NUMBER}&lt;/code&gt; already has the value equal to the number of pages. Let’s see the preview:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/04/convenient-reporting-with-jasper/page1.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/04/convenient-reporting-with-jasper/page2.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Again, we don’t need to worry about the missing image icons, since this is only a preview and this is the actual result:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/04/convenient-reporting-with-jasper/prod-page1.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/04/convenient-reporting-with-jasper/prod-page2.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;Since we have a few interfaces that we need to respect, we can easily integrate Hibernate with our Jasper reports as data source, we just need to make sure we are using the field and data source interfaces they defined. &lt;a href=&#34;https://developer.jboss.org/docs/DOC-14025&#34;&gt;Here&lt;/a&gt; we have a few examples, notably the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;List&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;cats&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;session.&lt;span style=&#34;color:#369&#34;&gt;find&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;from eg.Cat&amp;#34;&lt;/span&gt;);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;Map&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;parameters&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;HashMap();&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;parameters.&lt;span style=&#34;color:#369&#34;&gt;put&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Title&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;The Cat Report&amp;#34;&lt;/span&gt;);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;InputStream&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;reportStream&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;.&lt;span style=&#34;color:#369&#34;&gt;getResourceAsStream&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/the-cat-report.xml&amp;#34;&lt;/span&gt;);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;JasperDesign&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;jasperDesign&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;JasperManager.&lt;span style=&#34;color:#369&#34;&gt;loadXmlDesign&lt;/span&gt;(reportStream);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;JasperReport&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;jasperReport&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;JasperManager.&lt;span style=&#34;color:#369&#34;&gt;compileReport&lt;/span&gt;(jasperDesign);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;JRBeanCollectionDataSource&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;ds&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;JRBeanCollectionDataSource(cats);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;JasperPrint&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;jasperPrint&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;JasperManager.&lt;span style=&#34;color:#369&#34;&gt;fillReport&lt;/span&gt;(jasperReport,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;parameters,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;ds);&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;JasperManager.&lt;span style=&#34;color:#369&#34;&gt;printReportToPdfFile&lt;/span&gt;(jasperPrint,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;the-cat-report.pdf&amp;#34;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We gather a &lt;code&gt;List&lt;/code&gt; of &lt;code&gt;Cat&lt;/code&gt; instances, then define some parameters, like &lt;code&gt;Title&lt;/code&gt;, followed by the creation of an &lt;code&gt;InputStream&lt;/code&gt; object which will be used to generate a &lt;code&gt;JasperDesign&lt;/code&gt; object, which is then the input for the instantiation of &lt;code&gt;JasperReport&lt;/code&gt;. Now, we define &lt;code&gt;cats&lt;/code&gt; to be our data source and call &lt;code&gt;fillReport&lt;/code&gt;, passing the &lt;code&gt;jasperReport&lt;/code&gt; object we have just created, the parameters, which contain the title and the data source. Finally, we print the report to a PDF. Note that you can use a compiled .jasper file as input for &lt;code&gt;getResourceAsStream&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;tibco-jaspersoft-studio&#34;&gt;TIBCO Jaspersoft Studio&lt;/h3&gt;
&lt;p&gt;This IDE is excellent for compiling the jrxml files into jasper files. I use it as a desktop application. There are three tabs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Design&lt;/li&gt;
&lt;li&gt;Source&lt;/li&gt;
&lt;li&gt;Preview&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the Design tab one can interactively design the report, not worrying about source code, XML, and the like, which enables non-programmers to work on report creation as well. Handling the variables, parameters and fields needs some algorithmic understanding, but nonetheless, code is generated interactively in a point-and-click manner. The designer cannot do everything we need, but the Source tab comes to the rescue if needed. Sometimes I do not even need to use the Source tab.&lt;/p&gt;
&lt;p&gt;There’s still one problem: testing is a high-cost operation in the project I am using Jasper for. We need to build the .jasper files, but that’s low-cost. The higher cost is that we need to build the application that actually generates the Jasper reports in order to test and then deploy it with JBoss. Then the actual test in the application occurs, so a test takes more than a minute. Luckily there is a Preview tab, where I can more or less see whether it’s a good idea to invest time into building and deploying, or if we need to do some tweaking first.&lt;/p&gt;
&lt;h3 id=&#34;long-story-short&#34;&gt;Long story short&lt;/h3&gt;
&lt;p&gt;For more information, see Jaspersoft’s &lt;a href=&#34;https://www.jaspersoft.com/&#34;&gt;website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;JasperReports is free and open source. However, you have to pay a fee to consult the help documentation. It’s easily a competitor in quality with other reporting tools, which are less reasonably priced. When I first had to work with Jasper reports, I didn’t know anything about it, but was able to complete the tasks at hand in a few hours, which shows that getting into the Jasper universe isn’t too hard. One may have difficulty understanding .jrxml files at first, but trust me, it’s worth it.&lt;/p&gt;
&lt;p&gt;If you are already using Java and want to generate reports, Jasper is a good candidate. It can periodically generate reports for you and even send them attached to an email to you. I couldn’t write better closing words than a poster I found:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/04/convenient-reporting-with-jasper/breaking-news.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;p&gt;* Domo plan pricing was found at &lt;a href=&#34;http://web.archive.org/web/20170703124941/https://www.yurbi.com/blog/everything-need-know-domos-new-pricing-page/&#34;&gt;yurbi.com&lt;/a&gt;.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>MediaWiki extensions and wfLoadExtensionMessages</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/05/mediawiki-extensions-and/"/>
      <id>https://www.endpointdev.com/blog/2014/05/mediawiki-extensions-and/</id>
      <published>2014-05-09T00:00:00+00:00</published>
      <author>
        <name>Greg Sabino Mullane</name>
      </author>
      <content type="html">
        &lt;div class=&#34;separator&#34; style=&#34;clear: both; float: right; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2014/05/mediawiki-extensions-and/image-0.jpeg&#34; imageanchor=&#34;1&#34; style=&#34;clear: right; margin-bottom: 1em; margin-left: 1em;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2014/05/mediawiki-extensions-and/image-0.jpeg&#34;/&gt;&lt;/a&gt;&lt;br/&gt;&lt;small&gt;&lt;a href=&#34;https://flic.kr/p/dykcFR&#34;&gt;Image&lt;/a&gt; by &lt;a href=&#34;https://www.flickr.com/photos/yukonlife/&#34;&gt;Susan Drury&lt;/a&gt;&lt;/small&gt;
&lt;/div&gt;
&lt;p&gt;Upgrading MediaWiki can be a challenging task, especially if you use a lot of extensions.
While the core upgrade process usually goes smoothly, it’s rare you can upgrade a major
version or two without having to muddle with your collection of extensions. Extensions are bits of code that extend what MediaWiki can do. Only a few are packaged with and maintained alongside MediaWiki itself—​the great majority are written by third-party developers. When the MediaWiki API changes, it is up to those developers to update their extension so it works with the new version of MediaWiki. This does not always happen. Take for example one of the more common errors seen on a MediaWiki upgrade since 1.21 was released:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[Tue May 06 11:21:52 2014] [error] [client 12.34.56.78] PHP Fatal error:  Call to undefined function wfLoadExtensionMessages() in /home/beckett/mediawiki/extensions/PdfExport/PdfExport.php on line 83, referer: http://test.ziggy.com/wiki/Main_Page&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is because the &lt;strong&gt;wfLoadExtensionMessages&lt;/strong&gt; function, which many extensions use, has
been deprecated since MediaWiki version 1.16 and was finally removed in 1.21, resulting in the
error seen above. Luckily, this function has been a no-op since 1.16, so it is safe
to comment it out and/or make a dummy function in your LocalSettings.php file (see below).&lt;/p&gt;
&lt;p&gt;Sadly, the release notes for 1.21 make no mention of
&lt;a href=&#34;https://lists.gt.net/wiki/wikitech/214619&#34;&gt;this fairly major change&lt;/a&gt;. Let’s
walk through as if we didn’t know anything about it and see how we could solve the
given error with the help of git. For this example, we’ll use the
&lt;a href=&#34;https://www.mediawiki.org/wiki/Extension:Pdf_Export&#34;&gt;Pdf Export extension&lt;/a&gt;,
which allows you to export your wiki pages into PDF form. A pretty handy extension, and
one which completely fails to work in MediaWiki version 1.21 or better.&lt;/p&gt;
&lt;p&gt;First, let’s verify that wfLoadExtensionMessages does not exist at all in version 1.21 of MediaWiki. For
these examples, I’ve checked out the MediaWiki code via git, and am relying on
the fact that lightweight git tags were made for all the versions we are interested in.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git clone https://github.com/SemanticMediaWiki/SemanticMediaWiki.git mediawiki
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd mediawiki
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git grep wfLoadExtensionMessages 1.21.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.21.0:HISTORY:* (bug 12880) wfLoadExtensionMessages does not use $fallback from MessagesXx.php&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A nice feature of &lt;code&gt;git grep&lt;/code&gt; is the ability to simply use a tag after the search string. In this
case, we see that the only mention of wfLoadExtensionMessages in the entire codebase is an
old mention of it in the history file. Let’s see what version that bug is from:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git grep -n wfLoadExtensionMessages 1.21.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.21.0:HISTORY:5280:* (bug 12880) wfLoadExtensionMessages does not use $fallback from MessagesXx.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git show 1.21.0:HISTORY | head -5280 | tac | grep &amp;#39;===&amp;#39; -m1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=== Bug fixes in 1.12 ===&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That message is from way back in version 1.12, and doesn’t concern us. Let’s take a look at
what tags exist in the 1.20 branch so we can scan the latest one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git tag | grep &amp;#39;^1\.20&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.0rc1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.0rc2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.5
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.8&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we can peek inside version 1.20.8 and see what that function did before it was removed.
By using the -A and -B (after and before) arguments to grep, we can see the entire function in
context:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git grep wfLoadExtensionMessages 1.20.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.0:HISTORY:* (bug 12880) wfLoadExtensionMessages does not use $fallback from MessagesXx.php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1.20.0:includes/GlobalFunctions.php:function wfLoadExtensionMessages() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git show 1.20.8:includes/GlobalFunctions.php | grep -B6 -A2 LoadExtensionMessages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; * Load an extension messages file
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; * @deprecated since 1.16, warnings in 1.18, remove in 1.20
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; * @codeCoverageIgnore
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; */
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;function wfLoadExtensionMessages() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    wfDeprecated( __FUNCTION__, &amp;#39;1.16&amp;#39; );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Thus wfLoadExtensionMessages was basically a no-op in MediaWiki version 1.20, with the caveat that it will write
a deprecation warning to your error log (or, in modern versions, the debug log unless $wgDevelopmentWarnings is set).
Next we want to find the last time this function did something useful—​which should be version 1.15 according to
the comment above. Thus:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git show 1.15.0:includes/GlobalFunctions.php | grep -A4 LoadExtensionMessages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;function wfLoadExtensionMessages( $extensionName, $langcode = false ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    global $wgExtensionMessagesFiles, $wgMessageCache, $wgLang, $wgContLang;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    #For recording whether extension message files have been loaded in a given language.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    static $loaded = array();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So, it’s a pretty safe bet that unless you are upgrading from 1.15.0 or earlier, it should
be completely safe to remove it. When was 1.16.0 released? There are no dates in the HISTORY
file (shame), but the date it was tagged should be a good guess:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git show 1.16.0 | grep -m1 Date
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Date:   Wed Jul 28 07:11:03 2010 +0000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So what should you do with extensions that are still using this deprecated function? There are
two quick solutions: comment it out inside the extension, or add a dummy function to your version
of MediaWiki.&lt;/p&gt;
&lt;p&gt;Changing the extension itself is certainly quick and easy. To get the PdfExport extension to work,
we only have to comments out two calls to wfLoadExtensionMessages inside of the file
PdfExport.php, and one inside of PdfExport_body.php. The diff:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git difftool -y -x &amp;#34;diff -u1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--- /tmp/7YqvXv_PdfExport.php 2014-05-08 12:45:03 -0400
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+++ PdfExport.php             2014-05-08 12:34:39 -0400
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -82,3 +82,3 @@
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   if ($img_page &amp;gt; 0 || $img_page === false) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-        wfLoadExtensionMessages(&amp;#39;PdfPrint&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+        //wfLoadExtensionMessages(&amp;#39;PdfPrint&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                $nav_urls[&amp;#39;pdfprint&amp;#39;] = array(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -92,3 +92,3 @@
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; function wfSpecialPdfToolbox (&amp;amp;$monobook) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-          wfLoadExtensionMessages(&amp;#39;PdfPrint&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+          //wfLoadExtensionMessages(&amp;#39;PdfPrint&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           if (isset($monobook-&amp;gt;data[&amp;#39;nav_urls&amp;#39;][&amp;#39;pdfprint&amp;#39;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--- /tmp/7gO8Hz_PdfExport_body.php   2014-05-08 12:45:03 -0400
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+++ PdfExport_body.php               2014-05-08 12:34:44 -0400
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@@ -44,3 +44,3 @@
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            // For backwards compatibility
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-             wfLoadExtensionMessages(&amp;#39;PdfPrint&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+             //wfLoadExtensionMessages(&amp;#39;PdfPrint&amp;#39;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A better way is to add a dummy function to LocalSettings.php. This ensures that any extension
we add in the future will continue to work unmodified. Just throw this at the bottom
on your LocalSettings.php:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;wfLoadExtensionMessages&lt;/span&gt;() { }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Probably the best overall solution is to not only add that to your LocalSettings.php,
but to try to get the extension changed as well. You can notify the author, or try to
fix it yourself and release a new version if the extension has been abandoned. You might
also look to see if the extension has been superseded by a different extension, as sometime
happens.&lt;/p&gt;
&lt;p&gt;While there may be other compatibility issues when upgrading MediaWiki, for some extensions
(such as PdfExport), this is the only change needed to make it work again on newer versions of MediaWiki!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Little Spree Big Performance Problems</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/08/little-spree-big-performance-problems/"/>
      <id>https://www.endpointdev.com/blog/2013/08/little-spree-big-performance-problems/</id>
      <published>2013-08-05T00:00:00+00:00</published>
      <author>
        <name>Marina Lohova</name>
      </author>
      <content type="html">
        &lt;p&gt;Recently I worked on an online food store serving an area with very little infrastructure. As a result, the orders tended to be really big with lots of products.&lt;/p&gt;
&lt;p&gt;The website worked in the following environment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ruby 1.9.2&lt;/li&gt;
&lt;li&gt;Spree 0.60&lt;/li&gt;
&lt;li&gt;Heroku, Bamboo stack&lt;/li&gt;
&lt;li&gt;PostgreSQL 9.2.4&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;h12-timeout-errors&#34;&gt;H12 timeout errors&lt;/h3&gt;
&lt;p&gt;The performance problems started when we migrated Bamboo to Cedar on Heroku and replaced Thin webserver with Unicorn. We started getting a lot of &lt;a href=&#34;https://devcenter.heroku.com/articles/request-timeout&#34;&gt;Heroku Request timeout errors - H12&lt;/a&gt;:&lt;/p&gt;
&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-0.png&#34;/&gt;
&lt;p&gt;The problems happened mostly when logging in to admin dashboard or during the checkout for the certain orders. H12 errors occur when a HTTP request takes longer than 30 seconds to complete. For example, if a Rails app takes 35 seconds to render the page, the HTTP router returns a 503 after 30 seconds and abandons the incomplete Rails request for good. The Rails request will keep working and logging the normal errorless execution. After completion, the request will indefinitely hang in the application dyno.&lt;/p&gt;
&lt;p&gt;We started debugging H12: we set Unicorn timeout to 20 seconds to prevent the runaway requests and installed the rack-timeout gem with the timeout of 10 seconds to raise an error on a slow request. It all came down to a trivial database timeout!&lt;/p&gt;
&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-1.png&#34;/&gt;
&lt;p&gt;The application source has not changed during the transition from Bamboo to Cedar, but apparently Cedar/Unicorn is much more sensitive to the troubled code. Below is the list of performance bottlenecks and solutions in Spree. Some of them exist in version 0.60 only, but a lot of them are still present in Spree 1.x, which means that your application may have them too.&lt;/p&gt;
&lt;h3 id=&#34;issue-1-real-time-reports&#34;&gt;Issue #1: Real-time reports&lt;/h3&gt;
&lt;p&gt;Let’s take a closer look at the earlier database timeout code. It came from Admin Dashboard and admin/overview_controller.rb.&lt;/p&gt;
&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-2.png&#34;/&gt;
&lt;p&gt;The “Best Selling variants&amp;quot; report was being calculated real-time right in the web process:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;best_selling_variants&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  li = &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;LineItem&lt;/span&gt;.includes(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:order&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      where(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;orders.state = &amp;#39;complete&amp;#39;&amp;#34;&lt;/span&gt;).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      sum(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:quantity&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:group&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:variant_id&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:limit&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Record counts in the database are large enough to crash the application on Heroku with the database timeout:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;irb(main):&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;001&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;&amp;gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;LineItem&lt;/span&gt;.count
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=&amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;162279&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;irb(main):&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;002&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;&amp;gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Order&lt;/span&gt;.count
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=&amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;13027&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;irb(main):&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;003&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;&amp;gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Variant&lt;/span&gt;.count
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=&amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;14418&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Other reports on the Dashboard experience the same problem. They would cause the timeout in turns when logging into Admin:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;top_grossing_variants&lt;/li&gt;
&lt;li&gt;best_selling_taxons&lt;/li&gt;
&lt;li&gt;last_five_orders&lt;/li&gt;
&lt;li&gt;biggest_spenders&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;solution&#34;&gt;Solution&lt;/h3&gt;
&lt;p&gt;Fortunately, in Spree 1.x the internal reporting system has been replaced with &lt;a href=&#34;https://web.archive.org/web/20130807090154/http://jirafe.com:80/&#34;&gt;Jirafe&lt;/a&gt;:&lt;/p&gt;
&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-3.png&#34;/&gt;
&lt;p&gt;If switching to Spree 1.x is not an option, another way is to move the calculation into a background job, using, for example, delayed_job gem and Heroku Scheduler Addon:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;task &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:statistics&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:environment&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Delayed&lt;/span&gt;::&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Job&lt;/span&gt;.enqueue &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;StatisticsJob&lt;/span&gt;.new
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;issue-2-large-numbers&#34;&gt;Issue #2: Large numbers&lt;/h3&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-4.jpeg&#34; style=&#34;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&#34; /&gt;&lt;/div&gt;
&lt;p&gt;It is an established fact that humans eat a lot! Think about an order of a thousand Heineken 6-pack cans&amp;hellip;&lt;/p&gt;
&lt;p&gt;Or even something like this:&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-5.png&#34;/&gt;&lt;/div&gt;
&lt;p&gt;or this:&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-6.jpeg&#34;/&gt;&lt;/div&gt;
&lt;p&gt;Spree, both 0.60 and 1.x, proved to have a huge problem if an order has a lot of line items and/or a large quantity of single line items. The potentially dangerous code can be found all over the place. Consider the following example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;InventoryUnit&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;ActiveRecord&lt;/span&gt;::&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Base&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;destroy_units&lt;/span&gt;(order, variant, quantity)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    variant_units = order.inventory_units.group_by(&amp;amp;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:variant_id&lt;/span&gt;)[variant.id].sort_by(&amp;amp;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:state&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    quantity.ceil.times &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      inventory_unit = variant_units.shift
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      inventory_unit.destroy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now imagine what will happen with the order from the first screenshot. We have 15100 inventory units for that one. They will be meticulously destroyed from the inventory one by one in a loop after the checkout. This method was born to crash the application!&lt;/p&gt;
&lt;h3 id=&#34;solution-1&#34;&gt;Solution&lt;/h3&gt;
&lt;p&gt;A simple mindful refactoring was enough to solve the problem for me. There is no need to call “destroy” in the loop for every single inventory unit because we can use the efficient “destroy_all” method. I’m sure this can be optimized further, but it was enough to get rid of the timeout:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;destroy_units&lt;/span&gt;(order, variant, quantity)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  variant_units = order.inventory_units.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    group_by(&amp;amp;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:variant_id&lt;/span&gt;)[variant.id].
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sort_by(&amp;amp;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:state&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  variant_units = variant_units.shift(quantity.ceil)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;InventoryUnit&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    where(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:order_id&lt;/span&gt; =&amp;gt; order.id,&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:variant_id&lt;/span&gt; =&amp;gt; variant.id).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    order(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;state asc&amp;#39;&lt;/span&gt;).limit(quantity.ceil).
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    destroy_all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;issue-3-real-time-emails&#34;&gt;Issue #3: Real-time emails&lt;/h3&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-4.jpeg&#34; style=&#34;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&#34; /&gt;&lt;/div&gt;
&lt;p&gt;All emails in Spree are sent in real-time.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Order&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;ActiveRecord&lt;/span&gt;::&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Base&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;finalize!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;OrderMailer&lt;/span&gt;.confirm_email(&lt;span style=&#34;color:#038&#34;&gt;self&lt;/span&gt;).deliver
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Why is it bad? Let’s look at the following example from my application:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;confirm_email&lt;/span&gt;(order)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  attachments[&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;invoice.pdf&amp;#34;&lt;/span&gt;] = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Content-type&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;application/pdf&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:content&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;OrderInvoice&lt;/span&gt;.new.to_pdf(order)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  mail(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:subject&lt;/span&gt;  =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Order #&amp;#39;&lt;/span&gt; + order.number,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:from&lt;/span&gt;   =&amp;gt;    &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Spree&lt;/span&gt;::&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Config&lt;/span&gt;[&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:order_from&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:to&lt;/span&gt; =&amp;gt; order.email)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In my application “confirm_email” was overridden and generated the PDF invoice. The invoice listed all the products in the order and had about 200 lines in it. Again, it lead to the H12 timeout error.&lt;/p&gt;
&lt;h3 id=&#34;solution-2&#34;&gt;Solution&lt;/h3&gt;
&lt;p&gt;All emails should be sent in the background rather than in the web request. First, because network operations can take a long time, and second, because generating an email can also be slow. For example, sending in the background can be accomplished using &lt;a href=&#34;https://github.com/collectiveidea/delayed_job&#34;&gt;delayed_job gem&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;OrderMailer&lt;/span&gt;.delay.confirm_email(&lt;span style=&#34;color:#038&#34;&gt;self&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;issue-4-lazy-loading&#34;&gt;Issue #4: Lazy-loading&lt;/h3&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-4.jpeg&#34; style=&#34;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&#34; /&gt;&lt;/div&gt;
&lt;p&gt;Ecommerce objects are usually complicated with a lot of associations. This is totally fine as long as you eager-load the associations that will be used most with the loaded object later on. In most cases, Spree does not preload associations for its orders. For example, in spree/base_controller.rb:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#33b&#34;&gt;@order&lt;/span&gt; = &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Order&lt;/span&gt;.find_by_number! params[&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:order_id&lt;/span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As the result, here is what I see in server console while loading the order display page on the frontend:&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-9.png&#34;/&gt;&lt;/div&gt;
&lt;p&gt;&amp;hellip;And five more screens like this! The associations of the order — line items, variants and products — generate an additional chain of queries to the database during lazy-loading.&lt;/p&gt;
&lt;h3 id=&#34;solution-eager-loading&#34;&gt;Solution: Eager-loading&lt;/h3&gt;
&lt;p&gt;If I modify the line from the controller like this&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#33b&#34;&gt;@order&lt;/span&gt; = &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Order&lt;/span&gt;.where(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:number&lt;/span&gt; =&amp;gt; params[&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:order_id&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         .includes(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:line_items&lt;/span&gt; =&amp;gt; {&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:product&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:taxons&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:variant&lt;/span&gt; =&amp;gt; [&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:product&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:option_values&lt;/span&gt;]})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         .includes(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:adjustments&lt;/span&gt;).first&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&amp;hellip;SQL queries will shrink down to this:&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-10.png&#34;/&gt;&lt;/div&gt;
&lt;p&gt;Eager-loading did the trick. Of course, not everything needs to be loaded eagerly, and the solution varies from case to case. It worked like charm in my case.&lt;/p&gt;
&lt;h3 id=&#34;issue-5-dangerous-code-all-over-the-place&#34;&gt;Issue #5: Dangerous code all over the place&lt;/h3&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-4.jpeg&#34; style=&#34;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&#34; /&gt;&lt;/div&gt;
&lt;p&gt;There a lot of places in the Spree source code that are not optimized for performance. We don’t need to look far for an example, because there is another killer method right near the &amp;ldquo;destroy_units&amp;rdquo; one we inspected earlier!&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;InventoryUnit&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;ActiveRecord&lt;/span&gt;::&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Base&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;create_units&lt;/span&gt;(order, variant, sold, back_order)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    shipment = order.shipments.detect {|shipment| !shipment.shipped? }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sold.ceil.times {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      order.inventory_units.create(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:variant&lt;/span&gt; =&amp;gt; variant, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:state&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;sold&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:shipment&lt;/span&gt; =&amp;gt; shipment)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    back_order.ceil.times {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      order.inventory_units.create(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:variant&lt;/span&gt; =&amp;gt; variant, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:state&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;backordered&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:shipment&lt;/span&gt; =&amp;gt; shipment)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;order.line_items.each &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt; |line_item|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  back_order = determine_backorder(order, variant, quantity)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sold = quantity - back_order
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  create_units(order, line_item.variant,  sold, back_order)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I received a timeout either in the “sold” or the “backorder” loop, but there wasn’t a time when I didn’t receive a timeout!&lt;/p&gt;
&lt;h3 id=&#34;solution-3&#34;&gt;Solution&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;create_units&lt;/span&gt;(order, variant, sold, back_order)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  shipment = order.shipments.detect {|shipment| !shipment.shipped? }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  values = sold.ceil.times.to_a.map { &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;(&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;order.id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;variant.id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;,&amp;#39;sold&amp;#39;,&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;shipment.id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;)&amp;#34;&lt;/span&gt; } +
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    back_order.ceil.times.to_a.map { &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;(&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;order.id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;variant.id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;,&amp;#39;backordered&amp;#39;,&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;shipment.id&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;)&amp;#34;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  values.in_groups_of(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;500&lt;/span&gt;, &lt;span style=&#34;color:#080&#34;&gt;false&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt; |group|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;InventoryUnit&lt;/span&gt;.connection.execute(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;INSERT INTO inventory_units(order_id, variant_id, state, shipment_id) VALUES &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;group.join(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;)&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Another example: every line item has the after_create and after_save callbacks. The callback invokes the  Order.update! method. Order.update! method calls update_totals method&amp;hellip;twice throughout the method.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;update_totals&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;self&lt;/span&gt;.payment_total = payments.completed.map(&amp;amp;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:amount&lt;/span&gt;).sum
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;self&lt;/span&gt;.item_total = line_items.map(&amp;amp;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:amount&lt;/span&gt;).sum
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;self&lt;/span&gt;.adjustment_total = adjustments.map(&amp;amp;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:amount&lt;/span&gt;).sum
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;self&lt;/span&gt;.total = item_total + adjustment_total
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now imagine the order from the second screenshot with a lot of line items. During the checkout “update_totals” will be called each time the line item is saved. Typically, this line would produce a timeout, because the  “line_items” association was, of course, not preloaded:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;line_items.map(&amp;amp;&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:amount&lt;/span&gt;).sum&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I couldn’t list every circumstance like that, because it would require a lot of context to explain the catch, but I can still say many times …&lt;/p&gt;
&lt;h3 id=&#34;no-long-running-tasks-in-the-web-request&#34;&gt;No long-running tasks in the web request!&lt;/h3&gt;
&lt;p&gt;Be it Spree, Heroku, or any other context, environment or platform, please, never do the following in the web process:&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2013/08/little-spree-big-performance-problems/image-12.png&#34; style=&#34;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&#34; /&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;(!!!) Heavy database usage (slow or numerous queries, N+1 queries)&lt;/li&gt;
&lt;li&gt;Sending an email&lt;/li&gt;
&lt;li&gt;Accessing a remote API (posting to Twitter, querying Flickr, etc.)&lt;/li&gt;
&lt;li&gt;Rendering an image or PDF&lt;/li&gt;
&lt;li&gt;Heavy computation (computing a fibonacci sequence, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Say “No” to all these things to ensure a much happier life for your application!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Generating PDF documents in the browser</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/03/generating-pdf-documents-in-browser/"/>
      <id>https://www.endpointdev.com/blog/2013/03/generating-pdf-documents-in-browser/</id>
      <published>2013-03-15T00:00:00+00:00</published>
      <author>
        <name>Kamil Ciemniewski</name>
      </author>
      <content type="html">
        &lt;h3 id=&#34;what-you-will-learn&#34;&gt;What you will learn&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;How to generate PDF documents in the browser with JavaScript&lt;/li&gt;
&lt;li&gt;How to generate them out of &lt;em&gt;normal&lt;/em&gt; HTML&lt;/li&gt;
&lt;li&gt;How to &lt;em&gt;open&lt;/em&gt; those PDFs in new windows&lt;/li&gt;
&lt;li&gt;How to render them inline inside the DOM&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;introduction&#34;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;Every once in a while as web developers we face the challenge of providing PDF documents for the data we have persisted in the database.&lt;/p&gt;
&lt;p&gt;The usual approach is to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;generate the document with a library / DSL in the language of the backend&lt;/li&gt;
&lt;li&gt;or—​generate &lt;em&gt;normal html&lt;/em&gt; view and use a utility like &lt;a href=&#34;https://wkhtmltopdf.org/&#34;&gt;wkhtmltopdf&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That works nice, but what if you’re developing an &lt;a href=&#34;https://en.wikipedia.org/wiki/Single-page_application&#34;&gt;SPA&lt;/a&gt; app which only consumes JSON data from its backend? Imagine a scenario when the backend isn’t capable of producing responses other than JSON data. What could you do there?&lt;/p&gt;
&lt;h3 id=&#34;the-solution&#34;&gt;The solution&lt;/h3&gt;
&lt;p&gt;Thanks to some very bright folks behind the &lt;a href=&#34;https://parall.ax/products/jspdf&#34;&gt;jsPDF&lt;/a&gt; library we have both above mentioned options right inside the browser.&lt;/p&gt;
&lt;p&gt;I strongly encourage you to visit their website. There is a nice live coding editor set up which reflects in real time the PDF your code is producing.&lt;/p&gt;
&lt;h3 id=&#34;using-the-dsl&#34;&gt;Using the DSL&lt;/h3&gt;
&lt;p&gt;The whole process looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1.&lt;/span&gt; create jsPDF object:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doc = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; jsPDF()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2.&lt;/span&gt; put something interesting &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;in&lt;/span&gt; there:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doc.setFontSize(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;22&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doc.text(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;20&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;20&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;This is a title&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doc.setFontSize(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;16&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doc.text(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;20&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;30&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;This is some normal sized text underneath.&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;3.&lt;/span&gt; choose some useful outlet:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doc.output(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;dataurlnewwindow&amp;#39;&lt;/span&gt;, {})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;where-is-the-documentation&#34;&gt;Where is the documentation?&lt;/h3&gt;
&lt;p&gt;One thing I didn’t like about the experience which was really great otherwise, was the fact that you could browse the Internet for hours without luck, looking for some useful docs for the library.&lt;/p&gt;
&lt;p&gt;For all of you who don’t know the shortcut yet, here it is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/MrRio/jsPDF.git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And in the &lt;em&gt;doc&lt;/em&gt; directory you will find nicely generated docs out of the project sourcesvery neat!&lt;/p&gt;
&lt;h3 id=&#34;can-i-generate-it-just-from-html&#34;&gt;Can I generate it just from HTML?&lt;/h3&gt;
&lt;p&gt;Yes you can. On the project’s website the authors are warning us that this feature is still &lt;strong&gt;experimental&lt;/strong&gt;. But I have to say that last time I used it, all went well and the code produces nice PDF to this day (yay!).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doc.fromHTML $(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;.report_web&amp;#39;&lt;/span&gt;).get(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;), &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;width&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;170&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;elementHandlers&amp;#39;&lt;/span&gt;: 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;LI&amp;#39;&lt;/span&gt;: (el, renderer) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; renderer.y &amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;250&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        doc.addPage()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        renderer.y = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        renderer.y += &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;H1&amp;#39;&lt;/span&gt;: (el, renderer) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      doc.setFontSize(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;14&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      doc.setFontStyle(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;bold&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      doc.text($(el).text(), &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10&lt;/span&gt;, renderer.y)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      doc.setFontSize(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;12&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      doc.setFontStyle(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;normal&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doc.output &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;dataurlnewwindow&amp;#39;&lt;/span&gt;, {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Take a look at the code above. &lt;em&gt;#fromHtml&lt;/em&gt; method takes the DOM element, margins, and a hash of options. From my experience the &lt;em&gt;elementHandlers&lt;/em&gt; attribute seems to be mandatory (I got errors without it).&lt;/p&gt;
&lt;p&gt;Every element handler is just a pair of capitalized tag name and the function which takes DOM element and the renderer context.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;renderer&lt;/em&gt; variable contains data of the current paragraph, the pdf internal object, settings object and x and y. You have to remember to &lt;strong&gt;change x and y variables yourself&lt;/strong&gt; after creating some content.&lt;/p&gt;
&lt;p&gt;One last thing to remember is that the handler can return either &lt;em&gt;true&lt;/em&gt; or &lt;em&gt;false&lt;/em&gt;. If it returns &lt;em&gt;true&lt;/em&gt;, then the engine will not create content out of the given DOM element on its own. Otherwise, after your handler finishes its execution, the engine will generate the content for you. So you can use those handlers to munge a few things in the output document or you can take over the whole control and do it &lt;em&gt;your way&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&#34;open-pdf-output-in-a-new-window&#34;&gt;Open PDF output in a new window&lt;/h3&gt;
&lt;p&gt;You may have notice in one of above examples, that we were simply creating new windows with PDF documents there.&lt;/p&gt;
&lt;p&gt;To recap, opening PDF documents in new window:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;doc.output &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;dataurlnewwindow&amp;#39;&lt;/span&gt;, {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;render-pdfs-in-the-dom&#34;&gt;Render PDFs in the DOM&lt;/h3&gt;
&lt;p&gt;Nesting the PDF document inside the DOM seems way cooler. To do so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;data = doc.output &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;dataurlstring&amp;#39;&lt;/span&gt;, {}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;#report&amp;#39;&lt;/span&gt;).html &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;lt;iframe src=&amp;#39;#{data}&amp;#39;&amp;gt;&amp;lt;/iframe&amp;gt;&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You will notice that the &lt;em&gt;#output&lt;/em&gt; method takes a string which tells it how you’d like to generate the PDF. If you specify the &lt;strong&gt;‘dataurlstring’&lt;/strong&gt; it will return a string containing the url data you use in your iframe. That is how the last example works.&lt;/p&gt;
&lt;p&gt;There is much more to jsPDF than shown in this short post. If you’re interested, you can browse the docs included in the projects repository. There are a lot of useful methods for creating almost any type of document you would want.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Appending one PDF to another using PDF Toolkit</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2011/11/appending-one-pdf-to-another-using-pdf/"/>
      <id>https://www.endpointdev.com/blog/2011/11/appending-one-pdf-to-another-using-pdf/</id>
      <published>2011-11-22T00:00:00+00:00</published>
      <author>
        <name>Brian Buchalter</name>
      </author>
      <content type="html">
        &lt;p&gt;Ever need to manipulate PDFs? Prefer the command line? Us too. Imagine you have a contract in PDF format. When people print, sign, and re-scan the contract, that’s good documentation of the signature, but the clarity of the original machine-readable text is lost and the the file’s size is unnecessarily large. One solution is to append the scanned signature page to the original contract document.&lt;/p&gt;
&lt;p&gt;There are many PDF editors out there which address this need. One command line solution that works well is PDF Labs’s &lt;a href=&#34;https://www.pdflabs.com/docs/pdftk-man-page/&#34;&gt;PDF Toolkit&lt;/a&gt;. Let’s look at how we would use PDF Toolkit to append one document to another.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pdftk contract.pdf scanned_contract.pdf cat output original_and_signed_contract.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With this command we now have both contracts in their entirety. What we really want is to just take the signature page and append it. Let’s revise our command a bit to only take the signature page using what PDF Toolkit calls handles.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pdftk &lt;span style=&#34;color:#369&#34;&gt;A&lt;/span&gt;=contract.pdf &lt;span style=&#34;color:#369&#34;&gt;B&lt;/span&gt;=scanned_contract.pdf cat A B5 output contract_with_signature_attached.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We’ve assigned each document to a handle (A and B), which allows us to define the order of the output as well as the pages we want to select for the output. With the argument B5 PDF Toolkit knows we only want the fifth page of the scanned_contract.pdf. Ranges are also supported, so we could write something like B4-5 too.&lt;/p&gt;
&lt;p&gt;Unfortunately, the scanned contract was scanned upside down, so let’s rotate 180 degrees by adding the -endS argument.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pdftk &lt;span style=&#34;color:#369&#34;&gt;A&lt;/span&gt;=contract.pdf &lt;span style=&#34;color:#369&#34;&gt;B&lt;/span&gt;=scanned_contract.pdf cat A B5-endS output contract_with_signature_attached.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;One notable issue I encountered while rotating individual pages was the inability to rotate and append only the first page. When specifying an option like B1-endS, the entire “B” document would be rotated and appended instead of just the first page. One other gotcha to remember: escape spaces and special characters when providing the names of documents. For example, if our document was named “scanned contract.pdf” we would need to do this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pdftk contract.pdf scanned&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\ &lt;/span&gt;contract.pdf cat output signed_contract.pdf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The PDF Toolkit is licensed under GNU General Public License (GPL) Version 2. PDF Labs’s website provides a host of other &lt;a href=&#34;https://www.pdflabs.com/docs/pdftk-cli-examples/&#34;&gt;examples&lt;/a&gt; including how to encrypt, password-protect, and repair PDFs.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Building Xpdf on Ubuntu</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2011/08/building-xpdf-on-ubuntu/"/>
      <id>https://www.endpointdev.com/blog/2011/08/building-xpdf-on-ubuntu/</id>
      <published>2011-08-31T00:00:00+00:00</published>
      <author>
        <name>Jon Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;It may happen that you need to use &lt;a href=&#34;https://www.xpdfreader.com/&#34;&gt;Xpdf&lt;/a&gt;, even though it no longer ships with &lt;a href=&#34;https://www.ubuntu.com/&#34;&gt;Ubuntu&lt;/a&gt; and is considered &amp;hellip; outdated? buggy? insecure? In any case, it still renders some PDFs that &lt;a href=&#34;https://poppler.freedesktop.org/&#34;&gt;Poppler&lt;/a&gt;-based viewers such as &lt;a href=&#34;https://wiki.gnome.org/Apps/Evince&#34;&gt;Evince&lt;/a&gt; don’t, or allows some troublesome PDFs to print as fonts and line art instead of a rasterized mess.&lt;/p&gt;
&lt;p&gt;Here’s how I built and installed xpdf 3.02 on Ubuntu 11.04 (Natty Narwhal) x86_64:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-get install libfreetype6-dev libmotif-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget ftp://ftp.foolabs.com/pub/xpdf/xpdf-3.02.tar.gz  &lt;span style=&#34;color:#888&#34;&gt;# now 3.03 is current&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar xzpf xpdf-3.02.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; xpdf-3.02
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./configure --with-freetype2-library=/usr/lib/x86_64-linux-gnu &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;    --with-freetype2-includes=/usr/include/freetype2 &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;    --with-Xm-library=/usr/lib &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;&lt;/span&gt;    --with-Xm-includes=/usr/include/Xm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# see lots of warnings!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo make install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That’s it. Not as nice as the old native Debian/Ubuntu packages, but gets the job done.&lt;/p&gt;

      </content>
    </entry>
  
</feed>
