<?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/casepointer/</id>
  <link href="https://www.endpointdev.com/blog/tags/casepointer/"/>
  <link href="https://www.endpointdev.com/blog/tags/casepointer/" rel="self"/>
  <updated>2024-06-03T00:00:00+00:00</updated>
  <author>
    <name>End Point Dev</name>
  </author>
  
    <entry>
      <title>End Point’s CasePointer business acquired by Deloitte</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2024/06/casepointer-acquired-by-deloitte/"/>
      <id>https://www.endpointdev.com/blog/2024/06/casepointer-acquired-by-deloitte/</id>
      <published>2024-06-03T00:00:00+00:00</published>
      <author>
        <name>Rick Peltzman</name>
      </author>
      <content type="html">
        &lt;p&gt;We are proud to announce that Deloitte has acquired the industry-leading public health disease surveillance business, CasePointer, from End Point Corporation as of June 1, 2024. This acquisition brings to Deloitte, End Point’s experienced and skilled software engineers, cloud developers, DevOps engineers, epidemiologists, and former public health officials.&lt;/p&gt;
&lt;p&gt;Since 2008, End Point’s CasePointer business has worked with open-source public health software to modernize tools, automate processes, improve the user experience, and provide better return on investment to state and local public health agencies for their disease surveillance and epidemiologic needs.&lt;/p&gt;
&lt;p&gt;Jon Jensen, End Point’s former chief technical officer, has joined Deloitte with this transaction. He said: “We are excited to work with Deloitte’s team of professionals and serve their broad client base. Together, we expect to make an even greater impact for government health organizations.”&lt;/p&gt;
&lt;p&gt;Deloitte is only acquiring assets, clients, and personnel related to End Point’s CasePointer business. All other business lines remain with End Point, including systems administration, database engineering, e-commerce programming, application development, and our immersive GIS platform, VisionPort.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&#34;https://www.deloitte.com/us/en/Industries/government-public/about/public-health-transformation.html&#34;&gt;Deloitte’s Public Health Transformation&lt;/a&gt; website for further information.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Achieving Healthcare Data Interoperability</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2023/07/achieving-healthcare-data-interoperability/"/>
      <id>https://www.endpointdev.com/blog/2023/07/achieving-healthcare-data-interoperability/</id>
      <published>2023-07-28T00:00:00+00:00</published>
      <author>
        <name>Jarrett Smolarkiewicz</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2023/07/achieving-healthcare-data-interoperability/a_stream_running_between_houses_and_a_road.webp&#34; alt=&#34;An impressionist watercolor scene of two red-roofed farm houses with a tree-lined path leading forward on the left side of the image. The brushstrokes are very loose.&#34;&gt;&lt;/p&gt;
&lt;!-- Image: Johan Barthold Jongkind, A Stream Running between Houses and a Road, 19th century. Public domain under CC0. --&gt;
&lt;p&gt;(Co-authored by &lt;a href=&#34;/team/jon-jensen/&#34;&gt;Jon Jensen&lt;/a&gt;.)&lt;/p&gt;
&lt;h3 id=&#34;background&#34;&gt;Background&lt;/h3&gt;
&lt;p&gt;For many years, healthcare providers, public health experts, and software developers have been hard at work on standards and methods for interconnecting systems to share vast and ever-expanding patient and lab data.&lt;/p&gt;
&lt;p&gt;In the late 1980s the non-profit organization Health Level Seven International released the HL7 data standard. That was updated many times up to the year 2007 with &lt;a href=&#34;https://www.hl7.org/implement/standards/product_brief.cfm?product_id=144&#34;&gt;HL7 v2.5.1&lt;/a&gt; which is still widely used today.&lt;/p&gt;
&lt;p&gt;New healthcare data standards have emerged, including &lt;a href=&#34;https://www.hl7.org/implement/standards/product_section.cfm?section=14&#34;&gt;HL7 v3&lt;/a&gt;, the Consolidated Clinical Document Architecture (&lt;a href=&#34;https://www.hl7.org/implement/standards/product_brief.cfm?product_id=492&#34;&gt;C-CDA&lt;/a&gt;), the Fast Healthcare Interoperability Resource (&lt;a href=&#34;https://www.hl7.org/implement/standards/product_brief.cfm?product_id=491&#34;&gt;FHIR&lt;/a&gt;, pronounced &amp;ldquo;fire&amp;rdquo;), and more. These are not yet as broadly adopted as HL7 v2.5.1.&lt;/p&gt;
&lt;p&gt;Under the Health Insurance Portability and Accountability Act of 1996 (&lt;a href=&#34;https://www.hhs.gov/sites/default/files/ocr/privacy/hipaa/understanding/consumers/privacy-security-electronic-records.pdf&#34;&gt;HIPAA&lt;/a&gt;), most of this data is classified as PII (personally identifiable information) and/or PHI (personal health information) and must be kept secure and protected at all times, so that it will not be accessed without proper authorization or patient consent.&lt;/p&gt;
&lt;h3 id=&#34;the-data-dilemma&#34;&gt;The data dilemma&lt;/h3&gt;
&lt;p&gt;Healthcare data systems now routinely communicate in many ways, but there are sometimes incompatibilities when patient data travels from one system to another.&lt;/p&gt;
&lt;p&gt;The U.S. Centers for Disease Control (CDC) encourages and sometimes incentivizes, but does not mandate, adoption and implementation of common standards. So each jurisdiction&amp;rsquo;s public health agency (PHA), lab, and vendor may be using different and only partially overlapping standards.&lt;/p&gt;
&lt;p&gt;Different labs, doctors, and public health workers use varying conventions for things like facility names and lab codes, which presents problems for interpreting and reporting data. For example, “KU MAIN” may be recognized as the main campus of the University of Kansas Medical Center in nearby communities or states, while providers elsewhere may not recognize this code, or may mistake it for a similarly named facility in their area. The University of Kansas Health System consists of a large network of satellite facilities that span the states of Kansas and Missouri, rather than just one location in a single state. This may create additional confusion about which state jurisdictions should be involved.&lt;/p&gt;
&lt;p&gt;This semantic category is called a vocabulary, and if two systems use incompatible vocabulary, one of them, or an intermediary, must have a mapping from the terms in one vocabulary to another.&lt;/p&gt;
&lt;p&gt;The syntactic category of challenge is called a grammar, and covers the kinds of message types and actions a system works with.&lt;/p&gt;
&lt;p&gt;An article published in December 2022 by Dr. Naheed Ali identifies “inconsistent data and lack of standardized data structure” as the number one issue to be overcome regarding the &lt;a href=&#34;https://www.healthit.gov/faq/what-electronic-health-record-ehr&#34;&gt;Electronic Health Record (EHR)&lt;/a&gt; interoperability challenges facing healthcare professions today:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One of the biggest EHR interoperability challenges in healthcare interoperability is managing inconsistent data from multiple sources. Information stored in different databases can have a variety of formats and data types that are not easily compatible with one another. A single record may contain different information about a patient&amp;rsquo;s medical history or treatment plan, making it more difficult for different systems to interpret correctly.
—Dr. Naheed Ali, &lt;a href=&#34;https://www.ehrinpractice.com/ehr-interoperability-challenges-solutions.html&#34;&gt;EHR Interoperability Challenges and Solutions&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;cooperating-for-a-healthier-future&#34;&gt;Cooperating for a healthier future&lt;/h3&gt;
&lt;p&gt;Although great strides have been made to digitize healthcare data and improve interoperability, much remains to be done. Newer standards (like HL7 FHIR, released in 2014) face an uphill battle for industry adoption to become as widely utilized as HL7 v2.5.1 (from 2007) and C-CDA (from 2011).&lt;/p&gt;
&lt;p&gt;While networks of hospitals and laboratories typically set up EHR platforms built by companies like Cerner or Epic to manage patient data, public health agencies require additional applications to aid in the identification, tracking, and reporting of reportable health conditions from those patient EHRs.&lt;/p&gt;
&lt;p&gt;Public health services in the United States are provided by various federal, state, tribal, territorial, regional, municipal, and other bodies that decide which software they will use to support their communities. Some look to software offered by the CDC or software firms to provide the application functions they require. Others contract with consulting firms to develop custom software. Still others opt to develop and maintain everything in house.&lt;/p&gt;
&lt;p&gt;Getting so many diverse software systems to work together is difficult due to a phenomenon known as the quadratic cost problem. This occurs when the need for bi-directional connections between software applications increases exponentially, instead of linearly, with each component added to a system.&lt;/p&gt;
&lt;p&gt;An organization called TechChange explains this concept and more in their video &lt;a href=&#34;https://www.youtube.com/watch?v=KSEUh-wj7Y0&#34;&gt;Standards and Interoperability in Digital Health: Explained&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The book &lt;a href=&#34;https://www.ncbi.nlm.nih.gov/books/NBK216088/&#34;&gt;Patient Safety: Achieving a New Standard for Care&lt;/a&gt; identifies in chapter 4 this concern:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The fact that there is no standard means of representing the data for any of these datasets or requirements is astonishing and highlights the amount of unnecessary work performed by health care and regulatory organizations to prepare, transmit, and use what amount to custom reports.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Nearly 20 years after those words were written, and almost a decade after the FHIR standard was introduced, the variety of standards and systems has not narrowed. Change is difficult.&lt;/p&gt;
&lt;h3 id=&#34;health-information-exchanges&#34;&gt;Health Information Exchanges&lt;/h3&gt;
&lt;p&gt;One architectural attempt to simplify data sharing is by connecting applications of each jurisdictional segment within a larger governing body to a centralized &lt;a href=&#34;https://www.healthit.gov/topic/health-it-and-health-information-exchange-basics/what-hie&#34;&gt;Health Information Exchange (HIE)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;An example of this would be an individual state public health organization connecting its own software to an HIE, along with the software currently in use by each local jurisdiction within that state. Each jurisdiction does not have to use the same software, but can communicate by using its connection to the HIE rather than individual bi-directional connections to every other application used throughout the state.&lt;/p&gt;
&lt;p&gt;This sounds like just what is needed, and likely is for some use cases.&lt;/p&gt;
&lt;p&gt;But HIEs generally work at the syntactic (grammar) level. Many HIEs have agreements with the facilities they serve, that they will not change the content of messages in any way. Unfortunately that means most HIEs essentially work as a passthrough.&lt;/p&gt;
&lt;p&gt;They thus are helpless when it comes to the wide variety of nonstandard content semantics that they encounter, and have no way of correcting vocabularies, so they pass on junk data.&lt;/p&gt;
&lt;p&gt;Even a small, steady volume of unusable messages can at best clog up manual review queues and overwhelm already overworked staff, and at worst give a false sense that all data are being ingested and reported on, when they are not.&lt;/p&gt;
&lt;p&gt;Something like an HIE that is capable of semantic (vocabulary) inspection, translation, and rule-based routing, customizable per reporter for the jurisdiction&amp;rsquo;s changing needs, is called for.&lt;/p&gt;
&lt;h3 id=&#34;the-casepointer-software-suite&#34;&gt;The CasePointer software suite&lt;/h3&gt;
&lt;p&gt;We at End Point are solving the interoperability problem for our client jurisdictions’ public health disease surveillance with CasePointer, a new suite of proven open source software. It interoperates with many other systems, including HIEs, and is configurable to map varying local data conventions into a single system that routes messages and reporting as needed.&lt;/p&gt;
&lt;h4 id=&#34;epitrax-disease-surveillance-system&#34;&gt;EpiTrax disease surveillance system&lt;/h4&gt;
&lt;p&gt;We began in 2008 to work with software for public health using the open-source TriSano disease surveillance system.&lt;/p&gt;
&lt;p&gt;In 2017, the Utah Department of Health and Human Services (DHHS) released a new open source disease surveillance application called EpiTrax to replace their use of TriSano. EpiTrax is a more capable, comprehensive, and supportable application that supports &lt;a href=&#34;https://ndc.services.cdc.gov/&#34;&gt;all 170+ reportable health conditions&lt;/a&gt; identified by the &lt;a href=&#34;https://health.gov/healthypeople/objectives-and-data/data-sources-and-methods/data-sources/national-notifiable-diseases-surveillance-system-nndss&#34;&gt;National Notifiable Disease Surveillance System (NNDSS)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As open source software, we and others can use it, extend its capabilities, and contribute back to a shared source code repository.&lt;/p&gt;
&lt;p&gt;Today EpiTrax serves as the central application within the CasePointer suite.&lt;/p&gt;
&lt;h4 id=&#34;emsa-preprocessing-powerhouse&#34;&gt;EMSA preprocessing powerhouse&lt;/h4&gt;
&lt;p&gt;The separate application Electronic Message Staging Area (EMSA) was also designed by the team at Utah DHHS to work in tandem with EpiTrax. EMSA ingests electronic case and lab reports (eCRs &amp;amp; ELRs) from various reporters and allows public health organizations to create extremely powerful custom configurations capable of message inspection, semantic (vocabulary) mapping and transformation, and routing, tailored to each jurisdiction&amp;rsquo;s needs and preferences.&lt;/p&gt;
&lt;p&gt;Once these EMSA rules are set up, the healthcare data can flow continuously while automatically being pre-processed by EMSA according to its matching jurisdiction with minimal manual intervention by the area&amp;rsquo;s public health agency. PHA staff can focus on their primary objective: investigating and tracking disease to protect the health of their community.&lt;/p&gt;
&lt;p&gt;Investigators can customize their individual dashboards within EpiTrax to analyze, sort, trace, and process the data prepared by EMSA in the way that is most efficient for them. Working together, these two powerhouse applications provide the cost and time saving benefits that public health organizations around the country need.&lt;/p&gt;
&lt;h4 id=&#34;nmi-automatic-cdc-reporting&#34;&gt;NMI automatic CDC reporting&lt;/h4&gt;
&lt;p&gt;Once a public health case reaches a certain status within EpiTrax, certain data must be reported per current requirements of the CDC. Historically, this has been a manual and tedious process for investigators involving referencing a text file with the latest CDC guidelines as they process these reports.&lt;/p&gt;
&lt;p&gt;More recently, the &lt;a href=&#34;https://www.cdc.gov/nndss/about/history.html&#34;&gt;NNDSS Modernization Initiative (NMI)&lt;/a&gt; by the CDC has provided options for a much more automated method of reporting the necessary case data. This is a critical part of the process for PHAs, as they receive funding for their organization based on their ability to meet CDC reporting requirements and interoperability standards.&lt;/p&gt;
&lt;p&gt;The NMI module is integrated into the CasePointer workflow to ensure that once data reporting has been configured for a case, any updates will be automatically sent to the CDC without additional manual processing.&lt;/p&gt;
&lt;h4 id=&#34;casepointer-disease-reporting-portal&#34;&gt;CasePointer Disease Reporting Portal&lt;/h4&gt;
&lt;p&gt;During COVID-19, nontraditional reporters such as pharmacies, university health centers, community drive-up testing centers, and others not part of our state clients&amp;rsquo; formal public health infrastructure, needed to be able to submit test results to the state.&lt;/p&gt;
&lt;p&gt;We developed a specialized disease reporting portal, initially focusing on COVID-19, to accept simple batch uploads of test results and, based on changing policy, to forward test data to the disease surveillance system. This separate system had no access to the main EpiTrax disease surveillance system, or to any other reporters&amp;rsquo; data.&lt;/p&gt;
&lt;h3 id=&#34;bringing-it-all-together&#34;&gt;Bringing it all together&lt;/h3&gt;
&lt;p&gt;CasePointer provides two prominent strengths:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First, its ability to map the endless local conventions used by those reporting the data into a unified standard for the rest of the workflow.&lt;/li&gt;
&lt;li&gt;Second, the customizability and agility of the CasePointer applications are unique among available disease surveillance solutions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CasePointer puts the ability to customize data collection and surveillance in the hands of the public health experts. New fields can be added into an investigation form with the click of a button. The ability to quickly pivot and document disease information is critical in a quickly changing public health landscape.&lt;/p&gt;
&lt;h3 id=&#34;join-the-evolution-of-public-health-technology&#34;&gt;Join the evolution of public health technology&lt;/h3&gt;
&lt;p&gt;Such highly configurable, unified, robust tools can be a game changer for public health jurisdictions in need of an affordable, extensible solution that meet all their needs. CasePointer can even work to further streamline systems that are already integrated with an HIE.&lt;/p&gt;
&lt;p&gt;Within the United States, four states have already partnered with us to implement EpiTrax. We are helping them reduce unnecessary manual data processing costs, more effectively manage caseloads, and further automate their data workflows.&lt;/p&gt;
&lt;p&gt;If this piqued your curiosity, &lt;a href=&#34;/contact/&#34;&gt;contact us&lt;/a&gt; to learn more about CasePointer and how our team is evolving public health support with customized data solutions.&lt;/p&gt;
&lt;p&gt;We would love to support your efforts to protect the well-being of people and communities you care about!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>CSTE Conference 2023 Retrospective</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2023/07/cste-conference-2023-retrospective/"/>
      <id>https://www.endpointdev.com/blog/2023/07/cste-conference-2023-retrospective/</id>
      <published>2023-07-14T00:00:00+00:00</published>
      <author>
        <name>Samuel Stern</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2023/07/cste-conference-2023-retrospective/end-point-cste-team.webp&#34; alt=&#34;Seven members of the End Point CasePointer team standing in front of the CSTE 2023 press wall&#34;&gt;&lt;/p&gt;
&lt;p&gt;End Point is proud to have been an exhibitor at the 2023 Council of State and Territorial Epidemiologists (CSTE) conference in Salt Lake City, Utah.&lt;/p&gt;
&lt;p&gt;We are grateful to have had the opportunity to showcase our public health software suite offering, CasePointer, to numerous state, tribal, territorial, and international epidemiologists.&lt;/p&gt;
&lt;p&gt;The conference served as a meeting place to hear about the latest research in the fields of informatics and disease surveillance, and discuss the future of data management on state and national levels, with many talks exploring the technologies that will become future standards and practices.&lt;/p&gt;
&lt;p&gt;The End Point booth was abuzz with visitors getting hands-on demos using the EpiTrax software as well as learning about the other aspects of the CasePointer suite, such as the Electronic Message Staging Area (EMSA), our new disease reporting portal, and the EpiTrax NMI module.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2023/07/cste-conference-2023-retrospective/20230625_124940.webp&#34; alt=&#34;Trade show booth for CasePointer by End Point, featuring EpiTrax&#34;&gt;&lt;/p&gt;
&lt;p&gt;The CasePointer demo highlighted its capability of streamlining the management of epidemiological data with a user-friendly and highly customizable interface.&lt;/p&gt;
&lt;p&gt;The CSTE conference provides a valuable opportunity to engage with epidemiologists and gain insights into the daily obstacles they encounter in data reception, management, and sharing. It offers a platform to learn about their strategies for overcoming these challenges within their respective jurisdictions.&lt;/p&gt;
&lt;p&gt;One of the common topics that came up was tackling the challenge of file transfers using current protocols and systems in place. We were happy to share our successes using EMSA to customize how data is received and uploaded to EpiTrax, making transfers faster, more reliable, and easier to manage.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2023/07/cste-conference-2023-retrospective/20230627_154336.webp&#34; alt=&#34;Booth close-up with flyers, pens, etc. offered by End Point staffer whose name Samuel shows on his conference lanyard&#34;&gt;&lt;/p&gt;
&lt;p&gt;We look forward to further conversations with the visitors that stopped by our booth, and hope that you enjoyed the locally crafted chocolates and caramels and saved some for the trip home!&lt;/p&gt;
&lt;p&gt;Are you interested in a demo of the CasePointer suite? Reach out to us at &lt;a href=&#34;mailto:ask@endpointdev.com&#34;&gt;ask@endpointdev.com&lt;/a&gt; to set up a meeting.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Announcing CasePointer</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2023/06/announcing-casepointer-epitrax/"/>
      <id>https://www.endpointdev.com/blog/2023/06/announcing-casepointer-epitrax/</id>
      <published>2023-06-20T00:00:00+00:00</published>
      <author>
        <name>Jon Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2023/06/announcing-casepointer-epitrax/pexels-diva-plavalaguna-6147381.webp&#34; alt=&#34;Overhead view of 4 people standing on opposite sides of a table holding huge puzzle pieces&#34;&gt;&lt;br&gt;
Photo by &lt;a href=&#34;https://www.pexels.com/photo/close-up-photo-of-people-holding-puzzle-pieces-6147381/&#34;&gt;Diva Plavalaguna&lt;/a&gt;, Pexels license&lt;/p&gt;
&lt;p&gt;End Point is pleased to announce CasePointer, the expanded branding of our line of public health systems and services. Before this we referred to it simply by the name of one of its components, EpiTrax.&lt;/p&gt;
&lt;p&gt;The name CasePointer more appropriately reflects the broad scope of services we provide within the disease reporting and surveillance sector.&lt;/p&gt;
&lt;p&gt;This change coincides with the launching of the dedicated CasePointer website at www.casepointer.com and our participation next week in this year’s conference of CSTE (Council of State and Territorial Epidemiologists) in Salt Lake City, Utah. We will be staffing a booth there on the exhibition floor. Come visit us!&lt;/p&gt;
&lt;p&gt;Starting in 2008, End Point helped develop and maintain the TriSano open source disease surveillance system. In 2019 we migrated our customer, the Kansas Department of Health and Environment, from TriSano to a new disease surveillance system called EpiTrax, which was developed by the state of Utah, and is also open source.&lt;/p&gt;
&lt;p&gt;This timeline shows those and other key points on our journey:&lt;/p&gt;
&lt;p&gt;&lt;object style=&#34;max-width:100%&#34; type=&#34;image/svg+xml&#34; data=&#34;/blog/2023/06/announcing-casepointer-epitrax/casepointer-timeline-20230620.svg&#34;&gt;&lt;/object&gt;&lt;/p&gt;
&lt;p&gt;Due to the need for major additional features and capabilities, especially since the onset of the COVID-19 pandemic, End Point is now integrally involved with public health agencies in four states. For each of them we configured, deployed, maintain, and enhance the cloud hosting, relevant software, and databases to run those components they need, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the EpiTrax disease surveillance system&lt;/li&gt;
&lt;li&gt;EMSA (the Electronic Message Staging Area)&lt;/li&gt;
&lt;li&gt;the NMI (NNDSS Modernization Initiative) module&lt;/li&gt;
&lt;li&gt;End Point’s Disease Reporting Portal&lt;/li&gt;
&lt;li&gt;End Point’s merge tool&lt;/li&gt;
&lt;li&gt;Mirth Connect&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these interoperate harmoniously around the central EpiTrax application and database.&lt;/p&gt;
&lt;p&gt;Our team is composed of public health professionals, software engineers, database specialists, and security experts. We are committed to our public health clients and their needs. We are here to help you help our communities and look forward to discussing the CasePointer approach with you and your team.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>eCR Coordinator job opening</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2023/05/ecr-coordinator-job/"/>
      <id>https://www.endpointdev.com/blog/2023/05/ecr-coordinator-job/</id>
      <published>2023-05-23T00:00:00+00:00</published>
      <author>
        <name>Shannon Sandall</name>
      </author>
      <content type="html">
        &lt;img src=&#34;/blog/2020/11/job-java-javascript-developer/20201107-124658-crop.jpg&#34; alt=&#34;Person on boulder overlooking valley with lake&#34; /&gt;
&lt;!-- Photo by Jon Jensen --&gt;
&lt;p&gt;We are seeking a full-time &lt;strong&gt;Electronic Case Reporting (eCR) Coordinator&lt;/strong&gt; to provide high-level expertise in the validation and automation of eCR messages.&lt;/p&gt;
&lt;p&gt;This position is responsible for establishing complete, up-to-date, timely, and automated reporting of individual-level data, and automation of incoming EHR data. &lt;strong&gt;Position is remote, in the United States only.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The person in this role will be responsible for coordinating and overseeing the eCR onboarding process for our clients. Additionally, the person will become our subject matter expert for the NNDSS Modernization Initiative (NMI) and how systems in place within EpiTrax can be configured to report through the NMI module.&lt;/p&gt;
&lt;h3 id=&#34;job-responsibilities&#34;&gt;Job responsibilities&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;eCR onboarding—40%&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assist the on-boarding team with eCR reporters.&lt;/li&gt;
&lt;li&gt;Develop Structure, Dictionary, LOINC and SNOMED codes in EMSA.&lt;/li&gt;
&lt;li&gt;Assist in eCR message structure approval.&lt;/li&gt;
&lt;li&gt;Assist with EMSA management.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Troubleshooting—30%&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Issues found by the program epis and the LHDs.&lt;/li&gt;
&lt;li&gt;Issues found by the surveillance team.&lt;/li&gt;
&lt;li&gt;Create trouble tickets for issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Testing—15%&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Test the structure for incoming messages.&lt;/li&gt;
&lt;li&gt;Test new enhancement functionality.&lt;/li&gt;
&lt;li&gt;Test bug fixes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Grant document development—5%&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Assist with determining next steps in development to be included in grants.&lt;/li&gt;
&lt;li&gt;Develop documentation for grants.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Process documentation—5%&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thoroughly document changes and the processes put in place.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;NMI—5%&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Work with state and CDC teams to determine MMG onboarding schedule.&lt;/li&gt;
&lt;li&gt;Map EpiTrax variables to PHIN VAD variables in the NMI module.&lt;/li&gt;
&lt;li&gt;Document all mappings and changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;skills-required&#34;&gt;Skills required&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Working knowledge of public health surveillance or EHR and healthcare data&lt;/li&gt;
&lt;li&gt;Good communication skills, both spoken and written&lt;/li&gt;
&lt;li&gt;Ability to analyze problems&lt;/li&gt;
&lt;li&gt;Good testing skills&lt;/li&gt;
&lt;li&gt;Ability to multitask and set priorities&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;skills-to-have-or-to-learn-on-the-job&#34;&gt;Skills to have, or to learn on the job&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;In-depth knowledge of eCR messaging&lt;/li&gt;
&lt;li&gt;In-depth knowledge of EMSA&lt;/li&gt;
&lt;li&gt;In-depth knowledge of EpiTrax&lt;/li&gt;
&lt;li&gt;Working knowledge of NMI&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;For some of our clients you will need to submit to and pass a criminal background check.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;what-work-here-offers&#34;&gt;What work here offers:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Starting annual salary range: $50k–$85k&lt;/li&gt;
&lt;li&gt;Paid holidays (10 per year) and vacation (2 weeks per year)&lt;/li&gt;
&lt;li&gt;Health insurance subsidy and 401(k) retirement savings plan&lt;/li&gt;
&lt;li&gt;Collaboration with knowledgeable, friendly, helpful, and diligent co-workers around the world&lt;/li&gt;
&lt;li&gt;Freedom from being tied to one office location&lt;/li&gt;
&lt;li&gt;Flexible, sane work hours&lt;/li&gt;
&lt;li&gt;Annual bonus opportunity&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;get-in-touch-with-us&#34;&gt;Get in touch with us:&lt;/h3&gt;
&lt;p&gt;&lt;del&gt;Please email us an introduction to jobs@endpointdev.com to apply.&lt;/del&gt;
&lt;strong&gt;(This job has been filled.)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Include your location, a resume, your LinkedIn URL if you have one, and whatever else may help us get to know you.&lt;/p&gt;
&lt;p&gt;We look forward to hearing from you! Direct work seekers only, please—​this role is not for agencies or subcontractors.&lt;/p&gt;
&lt;p&gt;We are an equal opportunity employer and value diversity at our company. We do not discriminate on the basis of sex/​gender, race, religion, color, national origin, sexual orientation, age, marital status, veteran status, or disability status.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>How To Set Up pgTAP for Writing PostgreSQL Database Unit Tests</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2023/04/pgtap-for-database-unit-tests/"/>
      <id>https://www.endpointdev.com/blog/2023/04/pgtap-for-database-unit-tests/</id>
      <published>2023-04-12T00:00:00+00:00</published>
      <author>
        <name>Edgar Mlowe</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2023/04/pgtap-for-database-unit-tests/georgian-mountains.webp&#34; alt=&#34;A steep, green mountain slope divides the image with a steep diagonal downwards and to the right, reaching the bottom of the frame two thirds of the way to the right edge of the image. A small, red-roofed Georgian church sits on it. Another hill sinks down and to the left, creating an apex at the bottom. In the background, framed by these asymmetrical diagonals, is a tall, rocky ridgeline lined with snow anywhere the rocks aren&amp;rsquo;t too steep to hold it.&#34;&gt;&lt;/p&gt;
&lt;!-- Image by Seth Jensen, 2019 --&gt;
&lt;p&gt;In a previous blog post, my colleague Josh Tolley &lt;a href=&#34;/blog/2022/03/using-pgtap-automate-database-testing/&#34;&gt;introduced the concept&lt;/a&gt; of using pgTAP, a set of Postgres functions designed for writing unit tests within the database. This post will serve as a supplement to Josh&amp;rsquo;s post, focusing on the process of setting up pgTAP for testing a Postgres database.&lt;/p&gt;
&lt;h3 id=&#34;installing--setting-up-pgtap&#34;&gt;Installing &amp;amp; setting up pgTAP&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: make sure you have Postgres installed on your system. If you don&amp;rsquo;t have it, you can follow the &lt;a href=&#34;https://www.postgresql.org/download/&#34;&gt;Postgres documentation&lt;/a&gt; to learn how to install it.&lt;/p&gt;
&lt;p&gt;To install pgTAP for Postgres, you will need to follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Download the pgTAP source code from its GitHub repository.&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/pgtap/pgtap.git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Navigate to the &lt;code&gt;pgtap&lt;/code&gt; directory.&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;cd pgtap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install with &lt;code&gt;make&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-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make &amp;amp;&amp;amp; make install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, connect to your Postgres database using psql or any other Postgres client and run the following SQL command to create the pgTAP extension.&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;EXTENSION&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;pgtap;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now you should have pgTAP installed and ready to use in your Postgres database. If you face issues with installation, visit the &lt;a href=&#34;https://pgtap.org/documentation.html#installation&#34;&gt;pgTAP documentation&lt;/a&gt; for further help.&lt;/p&gt;
&lt;h3 id=&#34;writing-simple-database-tests-with-pgtap&#34;&gt;Writing simple database tests with pgTAP&lt;/h3&gt;
&lt;p&gt;Test to check if a table exists:&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;plan(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&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 style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;has_table(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;public&amp;#39;&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;#39;your_table&amp;#39;&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;#39;Table your_table should exist&amp;#39;&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 style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;finish();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Test to check if a column exists in a table:&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;plan(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&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 style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;has_column(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;public&amp;#39;&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;#39;your_table&amp;#39;&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;#39;your_column&amp;#39;&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;#39;Column your_column should exist in your_table&amp;#39;&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 style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;finish();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Test to check if a function returns the expected result:&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;plan(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&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 style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&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;is&lt;/span&gt;(your_function(),&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;expected_result,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;your_function() should return expected_result&amp;#39;&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 style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;finish();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;more-pgtap-tests&#34;&gt;More pgTAP tests&lt;/h3&gt;
&lt;h4 id=&#34;test-to-check-if-a-trigger-is-triggered&#34;&gt;Test to check if a trigger is triggered&lt;/h4&gt;
&lt;p&gt;Consider the following example. We have a table named &lt;code&gt;employees&lt;/code&gt; and a table named &lt;code&gt;audit_log&lt;/code&gt;. When a new employee is added to the &lt;code&gt;employees&lt;/code&gt; table, a trigger named &lt;code&gt;insert_employee_trigger&lt;/code&gt; fires and logs the new employee&amp;rsquo;s ID and creation timestamp in the &lt;code&gt;audit_log&lt;/code&gt; table. Let&amp;rsquo;s test if the trigger gets fired and produces the expected outcome.&lt;/p&gt;
&lt;p&gt;Create the tables.&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&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;TABLE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;employees&lt;span style=&#34;color:#bbb&#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;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;SERIAL&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;PRIMARY&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;KEY&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;name&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;VARCHAR&lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;255&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;NOT&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;NULL&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 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;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&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;TABLE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;audit_log&lt;span style=&#34;color:#bbb&#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;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;SERIAL&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;PRIMARY&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;KEY&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;employee_id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;INTEGER&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;NOT&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;NULL&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;created_at&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TIMESTAMP&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;NOT&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;NULL&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create the trigger and trigger 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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&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;OR&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;REPLACE&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;FUNCTION&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;insert_employee_trigger_function()&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 style=&#34;color:#080;font-weight:bold&#34;&gt;RETURNS&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;TRIGGER&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;AS&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#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;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;BEGIN&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 style=&#34;color:#080;font-weight:bold&#34;&gt;INSERT&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;INTO&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;audit_log&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(employee_id,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;created_at)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;VALUES&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;.id,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;NOW());&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 style=&#34;color:#080;font-weight:bold&#34;&gt;RETURN&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;&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 style=&#34;color:#080;font-weight:bold&#34;&gt;END&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 style=&#34;color:#a61717;background-color:#e3d2d2&#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;LANGUAGE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;plpgsql;&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;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&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;TRIGGER&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;insert_employee_trigger&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 style=&#34;color:#080;font-weight:bold&#34;&gt;AFTER&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;INSERT&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;ON&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;employees&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 style=&#34;color:#080;font-weight:bold&#34;&gt;FOR&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;EACH&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;ROW&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 style=&#34;color:#080;font-weight:bold&#34;&gt;EXECUTE&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;FUNCTION&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;insert_employee_trigger_function();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, write a test using pgTAP to test the trigger.&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;-- Set the test plan
&lt;/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;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;plan(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&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;&lt;span style=&#34;color:#888&#34;&gt;-- Prepare test data and perform operations that should fire the trigger
&lt;/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;INSERT&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;INTO&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;employees&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(name)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;VALUES&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;#39;John Doe&amp;#39;&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;&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 style=&#34;color:#888&#34;&gt;-- Check if the desired outcome of the trigger has occurred
&lt;/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;SELECT&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;is&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 style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;name&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;employees&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;WHERE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;id&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;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;employee_id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;audit_log&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;ORDER&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;BY&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;DESC&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;LIMIT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&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 style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;John Doe&amp;#39;&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 style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;The insert_employee_trigger should have been fired and produced the expected outcome&amp;#39;&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;test-to-check-if-a-constraint-is-enforced&#34;&gt;Test to check if a constraint is enforced&lt;/h4&gt;
&lt;p&gt;For this example, we&amp;rsquo;ll use the following two tables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;customers&lt;/code&gt; table with columns &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;orders&lt;/code&gt; table with columns &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;customer_id&lt;/code&gt;, and &lt;code&gt;amount&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is a foreign key constraint between the &lt;code&gt;orders&lt;/code&gt; table and the &lt;code&gt;customers&lt;/code&gt; table on the &lt;code&gt;customer_id&lt;/code&gt; column.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First, create the two tables and add the foreign key constraint.&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&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;TABLE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;customers&lt;span style=&#34;color:#bbb&#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;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;SERIAL&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;PRIMARY&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;KEY&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;name&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;VARCHAR&lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;255&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;NOT&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;NULL&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 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;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&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;TABLE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;orders&lt;span style=&#34;color:#bbb&#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;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;SERIAL&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;PRIMARY&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;KEY&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;customer_id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;INTEGER&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;REFERENCES&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;customers(id),&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;amount&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;INTEGER&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, create a test script named &lt;code&gt;fk_test.sql&lt;/code&gt; with the following content.&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;BEGIN&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;&lt;span style=&#34;color:#888&#34;&gt;-- Create test data in customers table
&lt;/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;INSERT&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;INTO&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;customers&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(id,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;name)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;VALUES&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&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;#39;Customer 1&amp;#39;&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;&lt;span style=&#34;color:#888&#34;&gt;-- Declare the number of tests
&lt;/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;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;plan(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&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;&lt;span style=&#34;color:#888&#34;&gt;-- Attempt to insert an order with an invalid customer_id
&lt;/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;-- This should fail due to the foreign key constraint
&lt;/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;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;throws_ok(&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 style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;INSERT INTO orders (id, customer_id, amount) VALUES (1, 969, 100);&amp;#39;&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 style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;23503&amp;#39;&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 style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;insert or update on table &amp;#34;orders&amp;#34; violates foreign key constraint &amp;#34;orders_customer_id_fkey&amp;#34;&amp;#39;&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 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;&lt;span style=&#34;color:#888&#34;&gt;-- Conclude the test and discard changes
&lt;/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;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;finish();&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 style=&#34;color:#080;font-weight:bold&#34;&gt;ROLLBACK&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;organizing-and-naming-your-test-files-based-on-test-anything-protocol-tap&#34;&gt;Organizing and naming your test files based on Test Anything Protocol (TAP)&lt;/h3&gt;
&lt;p&gt;Test Anything Protocol (TAP) is a convention for naming test files and organizing them within a project directory structure. The naming convention involves adding a numeric prefix to the test file name to indicate the order in which the tests should be run. For example, &lt;code&gt;00-test.sql&lt;/code&gt; is the first test file to be executed, followed by &lt;code&gt;01-another-test.sql&lt;/code&gt;, and so on.&lt;/p&gt;
&lt;p&gt;The project directory structure usually includes a directory called &lt;code&gt;t&lt;/code&gt; (short for &amp;ldquo;test&amp;rdquo;) under the project root directory. This &lt;code&gt;t&lt;/code&gt; directory contains all the test files following the TAP naming convention.&lt;/p&gt;
&lt;p&gt;Using this structure makes it easier to maintain and organize tests, as well as to run them in the correct order. This is especially important when tests depend on the results of previous tests, or when you want to ensure that tests are executed in a specific sequence.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example of a project directory structure using the TAP-related naming convention:&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;my_project/
&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;├─ src/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   ├── function1.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   ├── function2.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   └── function3.sql
&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;└─ t/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── 00-test.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── 01-another-test.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    └── 02-yet-another-test.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example, the project contains a &lt;code&gt;src&lt;/code&gt; directory for the source code (database functions) and a &lt;code&gt;t&lt;/code&gt; directory for the test files following the TAP naming convention.&lt;/p&gt;
&lt;h3 id=&#34;running-your-tests-using-pg_prove&#34;&gt;Running your tests using pg_prove&lt;/h3&gt;
&lt;p&gt;Now that we have written some tests using pgTAP, let&amp;rsquo;s see how we can run them. We&amp;rsquo;ll use pg_prove, a utility included with pgTAP, to automate the process and get a summary of the results.&lt;/p&gt;
&lt;p&gt;To run your tests with pg_prove, you&amp;rsquo;ll need to specify the name of the database you want to connect to and the path to your test file. For example, if your test file is located at &lt;code&gt;t/00-test.sql&lt;/code&gt; and your database is named &lt;code&gt;epitrax_db&lt;/code&gt;, you can run the following command:&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;pg_prove -d epitrax_db t/00-test.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When you run this command, pg_prove will execute all the tests in the specified file and print a summary of the results. The output will include the number of tests run, the number of tests passed, the number of tests failed, and any diagnostic messages or errors that were encountered.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example of what the output might look like:&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;t/00-test.sql .. ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;All tests successful.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;Files&lt;/span&gt;=1, &lt;span style=&#34;color:#369&#34;&gt;Tests&lt;/span&gt;=5,  &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt; wallclock secs ( 0.01 usr  0.00 sys +  0.02 cusr  0.00 &lt;span style=&#34;color:#369&#34;&gt;csys&lt;/span&gt; =  0.03 CPU)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Result: PASS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example, pg_prove ran one test file (&lt;code&gt;00-test.sql&lt;/code&gt;) and executed 5 tests. All of the tests passed, so the output shows that the result was PASS.&lt;/p&gt;
&lt;p&gt;If any of the tests fail, pg_prove will print a detailed report of the failures, including any error messages or diagnostic information. This can help you quickly identify and fix any issues in your code.&lt;/p&gt;
&lt;p&gt;Using pg_prove to automate your tests can save you a lot of time and effort, especially if you have a large number of tests to run. It also makes it easy to integrate your tests into your build process or continuous integration pipeline.&lt;/p&gt;
&lt;h3 id=&#34;pgtap-in-epitrax&#34;&gt;pgTAP in EpiTrax&lt;/h3&gt;
&lt;p&gt;EpiTrax relies on Postgres and its functions, making pgTAP an ideal tool for testing the platform&amp;rsquo;s database functions, ensuring data integrity, and maintaining the robustness of the system. By utilizing pgTAP, EpiTrax efficiently validates various aspects of its database structure and behavior.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;pgTAP database unit tests provide numerous benefits, including ensuring code quality and simplifying the testing process. This guide should serve as a starting point for setting up pgTAP, and we encourage you to explore the &lt;a href=&#34;https://pgtap.org/documentation.html#usingpgtap&#34;&gt;pgTAP documentation&lt;/a&gt; and read the &lt;a href=&#34;/blog/2022/03/using-pgtap-automate-database-testing/&#34;&gt;aforementioned blog post&lt;/a&gt; on automated database testing with pgTAP for more in-depth information on writing and running tests with pgTAP. By integrating pgTAP in projects like EpiTrax, it&amp;rsquo;s possible to improve overall database performance, stability, and security.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Identifying Vulnerabilities in Code Using Horusec</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2023/03/identifying-vulnerabilities-using-horusec/"/>
      <id>https://www.endpointdev.com/blog/2023/03/identifying-vulnerabilities-using-horusec/</id>
      <published>2023-03-28T00:00:00+00:00</published>
      <author>
        <name>Indra Pranesh Palanisamy</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2023/03/identifying-vulnerabilities-using-horusec/pexels-indra-pranesh-palanisamy-15837790.webp&#34; alt=&#34;The sun has just started to rise over the horizon. A group of fishermen can be seen pushing their small wooden boats into the water, preparing to start their day&amp;rsquo;s work. The air is still cool and quiet, with only the sound of waves gently lapping against the shore as the fishermen row out into the open sea, ready to begin their early morning fishing expedition.&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Indra Pranesh Palanisamy, 2022 --&gt;
&lt;p&gt;&lt;a href=&#34;https://horusec.io/site/&#34;&gt;Horusec&lt;/a&gt; is an open source tool which, by orchestrating other security tools, identifies security flaws and vulnerabilities in source code. It puts all the possible vulnerabilities it finds into a database for analysis.&lt;/p&gt;
&lt;p&gt;Currently, Horusec supports C#, Java, Kotlin, Python, Ruby, Go, JavaScript, TypeScript, PHP, Swift, C, Dart, Elixir, shell, Terraform, Kubernetes, nginx, HTML, and JSON. You can see an up-to-date list of &lt;a href=&#34;https://docs.horusec.io/docs/cli/analysis-tools/overview/#available-programming-languages-and-tools&#34;&gt;supported languages&lt;/a&gt; in Horusec&amp;rsquo;s docs.&lt;/p&gt;
&lt;p&gt;It can also be integrated with CI/CD to execute the scan every time a developer creates a pull request or merge request.&lt;/p&gt;
&lt;h3 id=&#34;horusec-cli-installation&#34;&gt;Horusec CLI Installation&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Requirements&lt;/strong&gt;: Docker, Git.&lt;/p&gt;
&lt;p&gt;The easiest installation method listed in the docs is &lt;code&gt;curl&lt;/code&gt;ing Horusec&amp;rsquo;s install script and piping it into &lt;code&gt;bash&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-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -fsSL https://raw.githubusercontent.com/ZupIT/horusec/main/deployments/scripts/install.sh | bash -s latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Be aware that there is risk to piping unseen commands into the shell like this: It can lead to unintended consequences and it is a bad security practice.&lt;/p&gt;
&lt;p&gt;If a user blindly pipes the output of a website response to be run by a shell without fully understanding what each command does, they may inadvertently execute malicious code or perform actions that could compromise the security of the system.&lt;/p&gt;
&lt;p&gt;To mitigate these risks, one solution is to use a virtual machine specifically set up for code scanning. This virtual machine should have no production data, no secret keys, and no other sensitive information. It should be used only for the purpose of scanning source code and nothing else.&lt;/p&gt;
&lt;p&gt;To instead download an executable directly, as well as for instructions for different platforms, see the &lt;a href=&#34;https://docs.horusec.io/docs/cli/installation/&#34;&gt;installation docs&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;vs-code-extension&#34;&gt;VS Code Extension&lt;/h3&gt;
&lt;p&gt;Horusec has a &lt;a href=&#34;https://docs.horusec.io/docs/extensions/visual-studio-code/&#34;&gt;VS Code extension&lt;/a&gt; which is helpful for making complete code analysis with a single click.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2023/03/identifying-vulnerabilities-using-horusec/horusec-vscode.webp&#34; alt=&#34;Screenshot of Horusec VS Code extension&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;usage&#34;&gt;Usage&lt;/h3&gt;
&lt;p&gt;Navigate to the application directory and run the &lt;code&gt;generate&lt;/code&gt; command to make a configuration file called &lt;code&gt;horusec-config.json&lt;/code&gt; which has a set of &lt;a href=&#34;https://docs.horusec.io/docs/cli/commands-and-flags/#global-flags&#34;&gt;customisations&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-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /path/to/project
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;horusec generate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;start&lt;/code&gt; command executes the code scan throughout the repository, searching for possible vulnerabilities:&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;horusec start -p . --output-format=json --json-output-file=&amp;lt;filename&amp;gt;.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All the detected vulnerabilities are stored in the named JSON output file.&lt;/p&gt;
&lt;h3 id=&#34;classification-of-vulnerabilities&#34;&gt;Classification of Vulnerabilities&lt;/h3&gt;
&lt;p&gt;Horusec may identify (or, as the docs say, accuse) possible vulnerabilities that aren&amp;rsquo;t vulnerabilities at all. Possible vulnerabilites need to be classified to sort out those that are wrong.&lt;/p&gt;
&lt;p&gt;Here are the classification types from &lt;a href=&#34;https://docs.horusec.io/docs/tutorials/how-to-classify-a-vulnerability/#classification-types&#34;&gt;Horusec&amp;rsquo;s docs&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;False positive:&lt;/strong&gt; Vulnerability found is wrong, because it is accused in a test file or it is not a vulnerability in fact, and is safe code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accepted Risk:&lt;/strong&gt; Vulnerability that was accused, but at the moment, you don&amp;rsquo;t have the option to correct it, so it is classified as an accepted risk to not raise alarms in future runs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Corrected:&lt;/strong&gt; Vulnerability that doesn&amp;rsquo;t exist and can be considered as corrected.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vulnerability:&lt;/strong&gt; A possible security problem found and accused by the analysis.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The hashes to be ignored can be added to the configuration file, &lt;code&gt;horusec-config.json&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-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:#a61717;background-color:#e3d2d2&#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;horusecCliFalsePositiveHashes&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;#34;f9e5abe187ad4246daa4e9113e0a11a175347e793fbc40acd7663df67b2f89d2&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;#34;878c35116d043311403a0a2e8a64f2c8d00479a1c23373dcd50372ff35e123c8&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:#b06;font-weight:bold&#34;&gt;&amp;#34;horusecCliRiskAcceptHashes&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;#34;5c9af42834ca77233a0e7afc98df317fb0e6041ea69a109754f278331039f844&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;#34;b494003277bcd7792390f032ba39e9a860da66ddb1ccfcd8a581978eab744561&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:#a61717;background-color:#e3d2d2&#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;h4 id=&#34;ignore-files&#34;&gt;Ignore Files&lt;/h4&gt;
&lt;p&gt;To entirely ignore a file or certain paths under the directory, add the paths to the configuration file:&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-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:#a61717;background-color:#e3d2d2&#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;horusecCliFilesOrPathsToIgnore&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;#34;**/tmp/**&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;#34;**/.vscode/**&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:#a61717;background-color:#e3d2d2&#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;h3 id=&#34;code-scanning-in-epitrax&#34;&gt;Code Scanning in EpiTrax&lt;/h3&gt;
&lt;p&gt;The use of a code scan tool has become an integral part of our work with the EpiTrax disease surveillance system for public health.&lt;/p&gt;
&lt;p&gt;By integrating Horusec into our software development process, we have been able to identify potential security vulnerabilities, code quality issues, and other problems before they can cause any significant harm.&lt;/p&gt;
&lt;p&gt;Moreover, it has helped us reduce the overall cost and time associated with bug-fixing and maintenance tasks, making our projects more efficient and effective. By automating the scanning process, we can identify problems quickly and accurately, allowing us to prioritize and address the most critical ones first.&lt;/p&gt;
&lt;p&gt;By leveraging the power of code scans, we can ensure that our code is of the highest quality, and our projects are as secure and reliable as possible.&lt;/p&gt;
&lt;br&gt;
&lt;p&gt;&lt;em&gt;Special thanks to my colleagues Kürşat Kutlu Aydemir and Edgar Mlowe for their insights and feedback on this blog post.&lt;/em&gt;&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Data Migration Tips</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2023/02/migration-tips-and-tricks/"/>
      <id>https://www.endpointdev.com/blog/2023/02/migration-tips-and-tricks/</id>
      <published>2023-02-04T00:00:00+00:00</published>
      <author>
        <name>Josh Tolley</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2023/02/migration-tips-and-tricks/leaves.webp&#34; alt=&#34;Scattered leaves on grass fill the frame, made up of many colors; green, cyan, pale and bright yellow, with red leaves providing highlights&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Seth Jensen, 2022 --&gt;
&lt;p&gt;When you&amp;rsquo;re in the business of selling software to people, you tend to get a few chances to migrate data from their legacy software to your shiny new system. Most recently for me that has involved public health data exported from legacy disease surveillance systems into &lt;a href=&#34;/expertise/postgresql/&#34;&gt;PostgreSQL databases&lt;/a&gt; for use by the open source EpiTrax system and its companion EMSA.&lt;/p&gt;
&lt;p&gt;We have collected a few tips that may help you learn from our successes,
as well as our &lt;del&gt;mistakes&lt;/del&gt;particularly educational experiences.&lt;/p&gt;
&lt;h3 id=&#34;customer-management&#34;&gt;Customer Management&lt;/h3&gt;
&lt;p&gt;Your job is to satisfy your customers, and &lt;strong&gt;your customers want to know how
the migration is progressing&lt;/strong&gt;. Give them an answer, even if it&amp;rsquo;s just a
generalization. This may be a burndown chart, a calculated percentage, a nifty
graphic, or whatever, but something your project managers can show to their
managers, to know more or less how far along things are.&lt;/p&gt;
&lt;p&gt;Your job is also to know your system; that&amp;rsquo;s not the customer&amp;rsquo;s job. They
shouldn&amp;rsquo;t have to get their data into a specific format for you to make use of
it. &lt;strong&gt;Be as flexible as possible&lt;/strong&gt; in the data format and structure
you&amp;rsquo;ll accept. In theory, so long as your customer can provide the legacy data
in a machine-readable format, you should be able to use it. Let them focus on
getting the data out of their legacy system — which is sometimes quite an
effort in itself! Real data is almost always messy data, and your customer will
probably want to take the opportunity to clean things up; make it as easy as
possible for them to do that, while still ensuring the migration proceeds
quickly and smoothly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Be careful about the vocabulary you use&lt;/strong&gt; with your customer. Your system and
the legacy system probably deal with the same kinds of data, and do generally
the same kinds of things. Of course, your software does it better than the
old &amp;rsquo;n&amp;rsquo; busted mess you&amp;rsquo;re replacing, but in order to be better, your software
has to be different from what it&amp;rsquo;s replacing. Different software means
different methods, different processes, and different concepts. You and your
customer might use the same words to mean totally different things, and unless
you&amp;rsquo;re careful, those differences can remain hidden well into the
implementation process, coming to light just in time to highlight some horrible
mistake you&amp;rsquo;ve made. Try to avoid that. Talk with your customer to make sure
your team and their team share a common vocabulary. If your system&amp;rsquo;s core
function is to track widgets, and their legacy system&amp;rsquo;s function is also to
track widgets, make sure you understand the differences between your software&amp;rsquo;s
concept of a widget and their legacy system&amp;rsquo;s concept of a widget.&lt;/p&gt;
&lt;h3 id=&#34;migration-scripting&#34;&gt;Migration Scripting&lt;/h3&gt;
&lt;p&gt;For our products and our customers, we&amp;rsquo;ve found pretty much every migration
process is different, and each one is a custom programming job. Your team
should &lt;strong&gt;decide at the beginning what steps the migration needs to include,
and what technologies it will use&lt;/strong&gt; in each step. Here at End Point, we often
like to work directly in the database, in SQL. Migrations are all about
manipulating data, and SQL is well suited for that task. With whatever
technology you use, decide how you&amp;rsquo;ll use it, to manage the considerations
given here. You can change your mind later and refactor accordingly, but always
have a plan you&amp;rsquo;re following.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Design the migration as a sequence of processes.&lt;/strong&gt; That is, first you might
import one type of record, next another type of record that depends on the
previous one, followed by several further steps to import data from a third
source, clean it, map values from the legacy system to the new system, validate
the results, and create records in the destination database. Of course the
steps will vary from project to project, but the point is your migration will
probably include several steps which need to be run in a specific order, so
plan your development conventions accordingly. At End Point, we often like to
&lt;strong&gt;put each step in a SQL file, and name each file beginning with a number&lt;/strong&gt;, so
you can run each script in order sorted by filename, and achieve the correct
result. We might have files called:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;01_import_products.sql&lt;/li&gt;
&lt;li&gt;02_import_customers.sql&lt;/li&gt;
&lt;li&gt;03_import_order_history.sql&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s also common to implement each step one at a time, and to need to run each
step several times as it&amp;rsquo;s being developed. We find it very helpful to &lt;strong&gt;wrap
each step in a transaction&lt;/strong&gt;. Often that means each SQL file begins with a
&lt;code&gt;BEGIN;&lt;/code&gt; statement, and ends with &lt;code&gt;COMMIT;&lt;/code&gt;. Often I&amp;rsquo;ll leave out the &lt;code&gt;COMMIT&lt;/code&gt;
until I&amp;rsquo;m finished working on a file. That way to work on the code I can open a
database session and run the migration script I&amp;rsquo;m working on, and when it
completes, it will leave me inside the open transaction where I can inspect the
results of my work. I make changes to the script, roll back the transaction,
and run the script again, for as many iterations as it takes. I only add a
&lt;code&gt;COMMIT&lt;/code&gt; when I&amp;rsquo;ve tested the whole file and think it&amp;rsquo;s ready for the next step
in testing.&lt;/p&gt;
&lt;p&gt;I mentioned above that the customer may want to use this opportunity to clean
their data. You should want this, too. &lt;strong&gt;Make sure the data you&amp;rsquo;re feeding your
new system is as clean and well-structured as possible.&lt;/strong&gt; You may find, as we
do, that most of the work in your migrations is in validating the input data,
and that actually creating new records in your application is almost an
afterthought. That&amp;rsquo;s OK. You may also find there are places where your
application, wonderful though it may be, could stand to be more strict about
the data it accepts. I have often discovered my application&amp;rsquo;s database needs a uniqueness
constraint, or a foreign key, thanks to a migration I was working on.&lt;/p&gt;
&lt;h3 id=&#34;data-migration-history&#34;&gt;Data Migration History&lt;/h3&gt;
&lt;p&gt;I wish I could truthfully claim all our migrations go off flawlessly, but that
would be a lie. It&amp;rsquo;s not unheard of to run into some corner case, a few weeks
or even months after the migration goes live, where data wasn&amp;rsquo;t migrated correctly.&lt;/p&gt;
&lt;p&gt;On the other hand, it&amp;rsquo;s certainly not uncommon for a customer or coworker to
spot something that strikes them as odd, after the migration goes live, only to
find later that everything was in fact correct. In either case, it&amp;rsquo;s important
to &lt;strong&gt;preserve a history of the migration&lt;/strong&gt; to investigate these concerns. We
accomplish this with a few specific steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a database schema for the migration, and a table within that schema for each data file or object type we&amp;rsquo;re importing.&lt;/strong&gt; I call these tables &amp;ldquo;staging tables&amp;rdquo;, where the incoming data is &amp;ldquo;staged&amp;rdquo; as it&amp;rsquo;s cleaned and validated. Having a separate schema means these tables can remain in the production database long after the migration is complete, generally without interfering with anything.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;These staging tables should generally &lt;strong&gt;use text fields, to be as forgiving and flexible as possible with the incoming data.&lt;/strong&gt; We can clean, parse, and reformat the data after it&amp;rsquo;s imported.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don&amp;rsquo;t change the data in these staging tables; add to the data instead.&lt;/strong&gt; In other words, if you need to map a value from the legacy system to a different value for your new system, don&amp;rsquo;t change the column you imported into the staging table; instead, add a new column to the staging table where you&amp;rsquo;ll store the re-mapped value. If you need to parse a text field into a date (because you followed the instruction to use text fields!), don&amp;rsquo;t change the type of an imported column; instead, add a new column of date or timestamp type, to store the parsed value. That way, when three months down the road someone discovers that some of the imported records have weird dates, you have all the information you need to determine whether the fault lies with the imported data or some step of the migration progress. Knowing exactly where the fault crept in leaves you that much more empowered to fix it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Keep track of your migrated records&amp;rsquo; primary keys, in the legacy system and the new system.&lt;/strong&gt; Imagine you&amp;rsquo;ve just imported your client&amp;rsquo;s legacy customer list into a staging table. This data includes the legacy system&amp;rsquo;s primary key. Add a new column to the table for your new system&amp;rsquo;s primary key, and populate it. Many of our systems use an integer sequence as a primary key, so we&amp;rsquo;d add a new integer column to the staging table, and fill it with the next values from the sequence. Following this principle will give you several important abilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can always connect a record in the legacy system with its corresponding record(s) in the new system. If you&amp;rsquo;ve imported a customer list in this fashion, then when you&amp;rsquo;re importing the order data later, and each order points to a customer using a legacy customer primary key, you can easily find the correct customer primary key to use in your system.&lt;/li&gt;
&lt;li&gt;You can easily know if a record in your system comes from the migration, or from normal day-to-day business. You will probably use this every time you try to debug something with your migration.&lt;/li&gt;
&lt;li&gt;If you need to remove all imported records and re-import them, you can identify exactly which records those are. This should be only rarely needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, &lt;strong&gt;document the decision making process, in comments directly in your
code.&lt;/strong&gt; For instance, if you have a table of mappings from one value to
another, chances are good you arrived at the final version of that mapping
table only after some discussion with the customer. Chances are also good
someone&amp;rsquo;s going to question it later on. It&amp;rsquo;s helpful to keep a comment around,
something like, &lt;code&gt;# Joe Rogers verified this is the correct mapping in the daily standup meeting, 23 Nov 2022&lt;/code&gt;. This is especially common if you
eventually decide to ignore a certain class of records. &lt;code&gt;/* Rebecca says ignore all records with type = &amp;quot;ARCHIVED&amp;quot;, via group email 9 Jan 2023 */&lt;/code&gt; is a very
helpful clue when someone comes around wondering where those records went.&lt;/p&gt;
&lt;h3 id=&#34;teamwork&#34;&gt;Teamwork&lt;/h3&gt;
&lt;p&gt;My remaining tips apply to almost any programming project. First, &lt;strong&gt;use source
control, and commit your code to it often.&lt;/strong&gt; I can&amp;rsquo;t count how often I&amp;rsquo;ve been
grateful the Git repository had a backup of my work, or made my work accessible
to fill some unexpected need on some other system, nor can I count how many
times I&amp;rsquo;ve been stuck because someone else didn&amp;rsquo;t commit their code so I
couldn&amp;rsquo;t get at it when I needed it.  Let&amp;rsquo;s not talk about how many times I&amp;rsquo;ve
caused someone else to get stuck in the same way&amp;hellip; Of course, don&amp;rsquo;t commit
your customer&amp;rsquo;s data. But you should commit your code, and commit it often.&lt;/p&gt;
&lt;p&gt;Finally, where possible, &lt;strong&gt;work with someone else.&lt;/strong&gt; Two programmers reviewing
each other&amp;rsquo;s code and collaborating on solutions are often far better than two
programmers working alone, or one programmer working twice as much.&lt;/p&gt;
&lt;p&gt;Speaking of working out solutions together, I&amp;rsquo;d love your help improving this
list. What keys have you found are important for data migration projects? I
welcome your comments. And if you&amp;rsquo;re looking for someone to handle a data
migration project for you, &lt;a href=&#34;/contact/&#34;&gt;give us a call&lt;/a&gt;!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Nevada State EpiTrax Launch</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2022/12/nevada-state-epitrax-launch/"/>
      <id>https://www.endpointdev.com/blog/2022/12/nevada-state-epitrax-launch/</id>
      <published>2022-12-01T00:00:00+00:00</published>
      <author>
        <name>Katrease Hale</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2022/12/nevada-state-epitrax-launch/desert.webp&#34; alt=&#34;Weathered red rocks jut out from the desert into the foreground, while a blue haze covers a mountain range in the background.&#34;&gt;
Photo by Adrien Drj&lt;/p&gt;
&lt;!-- Photo from Pexels: https://www.pexels.com/photo/signage-on-ground-near-brown-mountains-12965227/ --&gt;
&lt;p&gt;If COVID-19 has taught us anything, it is that the public health landscape can change quickly, and we need a disease surveillance system that is adaptable to support our ever-evolving climate.&lt;/p&gt;
&lt;p&gt;Having access to surveillance data for purposes of contact tracing, following trends, and monitoring evolving disease conditions allows health departments to be agile in response. This is a critical component in providing communities with a robust public health infrastructure.&lt;/p&gt;
&lt;p&gt;For all these reasons and many more, the State of Nevada embarked on a journey to migrate away from their surveillance system, NBS, to the open-source EpiTrax system created by the Utah Department of Health. Ultimately, the Nevada decisionmakers made this change because they needed to be on one state-wide system and wanted autonomy to customize the system.&lt;/p&gt;
&lt;p&gt;Nevada had been exploring this change for a while but due to unforeseen problems the window of time for implementation was incredibly narrow. In the first four months of End Point&amp;rsquo;s partnership with Nevada, the team was able to accomplish what was believed to be impossible in so short a time.&lt;/p&gt;
&lt;h3 id=&#34;the-four-month-sprint&#34;&gt;The Four Month Sprint&lt;/h3&gt;
&lt;p&gt;Some of the major milestones on the way to the new EpiTrax system included the following:&lt;/p&gt;
&lt;h4 id=&#34;building-out-custom-forms&#34;&gt;Building Out Custom Forms&lt;/h4&gt;
&lt;p&gt;EpiTrax is composed of core and form fields. Core fields are consistent across all conditions. Form fields allow jurisdictions to customize the data system to collect data specific to the needs of their area or the reporting requirements of their funders.&lt;/p&gt;
&lt;p&gt;In Nevada, we framed these forms to collect the data outlined in the Message Mapping Guide set forth by the CDC. Collecting form data is the first step in configuring the system to use the NMI module which allows for seamless reporting.&lt;/p&gt;
&lt;h4 id=&#34;configuring-the-system&#34;&gt;Configuring the System&lt;/h4&gt;
&lt;p&gt;EpiTrax is an intuitive system that is highly configurable. For example, EpiTrax will show specific fields by condition or condition type, allowing an investigator working on a COVID record to only see vaccines and treatments for COVID which reduces time and error in data entry.&lt;/p&gt;
&lt;p&gt;These parameters need to be defined and set up in the system for a large number of items. End Point was able to provide templates and examples from other states and having a framework for this documentation was vital.&lt;/p&gt;
&lt;h4 id=&#34;testing-the-system&#34;&gt;Testing the System&lt;/h4&gt;
&lt;p&gt;Testing sounds easy: “You just log in and make sure the functionality is there.” However, to adequately test a new environment with multiple jurisdictions and a variety of user groups takes time, attention, and follow-through.&lt;/p&gt;
&lt;p&gt;Nevada worked with End Point to bring in users from across the state to test both the functionality of the system and disease-specific variables. Then the test failures were discussed daily and the programmers provided options and support for resolving problems. After modifications were made to the environment the second round of testing was implemented.&lt;/p&gt;
&lt;p&gt;Given the tight window of time to launch EpiTrax we were building (testing) the ship as we were sailing it and this was only possible given the commitment of everyone on the team.&lt;/p&gt;
&lt;h4 id=&#34;training&#34;&gt;Training&lt;/h4&gt;
&lt;p&gt;You cannot launch a statewide system without training the end users, answering questions, and providing a mechanism for ongoing support. End Point provided countless trainings ranging from general use to administrative functionality of the system, and also provided Nevada with a user manual template that they were able to build on and grow to fit their needs.&lt;/p&gt;
&lt;h4 id=&#34;electronic-messaging-staging-area-emsa&#34;&gt;Electronic Messaging Staging Area (EMSA)&lt;/h4&gt;
&lt;p&gt;EMSA is an application that processes lab messages and delivers them into EpiTrax. The delivery of these messages is what creates the record for investigation in EpiTrax. Since this was a new process and system to Nevada, End Point worked with the Nevada team to configure the various vocabularies and rules.&lt;/p&gt;
&lt;h4 id=&#34;going-live&#34;&gt;Going Live&lt;/h4&gt;
&lt;p&gt;On September 12 EpiTrax officially launched in Nevada. End Point staff were there both in person and with a consistent virtual presence to work through user concerns, login issues, and workflow questions.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The customization and scope of EpiTrax are crucial components in allowing Nevada to optimize work processes, streamline the multiple data systems being used into one cohesive system, and greatly reduce redundancy.&lt;/p&gt;
&lt;p&gt;While switching systems can seem like a daunting and time-consuming task, so is continuing to operate in crisis mode with a system that stops your team from being dynamic. Any change for the better involving hundreds of people and a lot of data is going to take time, normally much longer than 4 months.&lt;/p&gt;
&lt;p&gt;The partnership between Nevada and End Point during this fast-paced launch has better positioned the state to use their data to support well-coordinated public health responses to emerging diseases or outbreaks.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>CSTE Conference EpiTrax retrospective</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2022/06/cste-conference-epitrax-retrospective/"/>
      <id>https://www.endpointdev.com/blog/2022/06/cste-conference-epitrax-retrospective/</id>
      <published>2022-06-29T00:00:00+00:00</published>
      <author>
        <name>Steve Yoman</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2022/06/cste-conference-epitrax-retrospective/end-pointers-booth-cste.webp&#34; alt=&#34;Banner photo of 4 End Pointers in our conference booth&#34;&gt;&lt;/p&gt;
&lt;p&gt;Last week we were in Louisville, Kentucky for the CSTE Conference. End Point staffed a conference booth to represent the EpiTrax public health surveillance system to a wonderful group of public health experts.&lt;/p&gt;
&lt;p&gt;You can read some background about the conference and CSTE in &lt;a href=&#34;/blog/2022/06/booth-at-cste-conference/&#34;&gt;our earlier blog post announcing our plans&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2022/06/cste-conference-epitrax-retrospective/attendees.webp&#34; alt=&#34;Photo of attendees at a CSTE conference session&#34;&gt;&lt;/p&gt;
&lt;p&gt;We really enjoyed meeting new friends in person after two years of canceled events due to the pandemic. We spoke with staff from health departments and disease surveillance teams from several state and local jurisdictions, as well as with experts from the CDC and other software and service vendors.&lt;/p&gt;
&lt;p&gt;One of the highlights was going around to meet other people staffing booths at the conference. It charged us up to see and hear about all of the interesting and innovative things going on in the public health space at a time when there is so much that needs to be done. We were particularly struck by the efforts being made in onboarding and distributing ELRs and eCRs, areas where the Electronic Message Staging Area (EMSA, which we deploy and support) can complement and enrich those activities.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2022/06/cste-conference-epitrax-retrospective/conference-hall.webp&#34; alt=&#34;Photo of CSTE conference hall&#34;&gt;&lt;/p&gt;
&lt;p&gt;The open-source disease surveillance and reporting software EMSA and EpiTrax both enjoyed well-deserved attention as we demonstrated them to numerous groups seeking better solutions to serve people in their jurisdictions. People were very interested in the functionality EpiTrax has for case management, encounters, and NMI reporting.&lt;/p&gt;
&lt;p&gt;Of course there is a lot more we could say about EpiTrax and EMSA. So, if you didn’t find us at the conference or if you are interested in what EpiTrax and EMSA can do, &lt;a href=&#34;/contact/&#34;&gt;contact us&lt;/a&gt; here online. We are happy to give you a demo!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>End Point booth at CSTE 2022 conference</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2022/06/booth-at-cste-conference/"/>
      <id>https://www.endpointdev.com/blog/2022/06/booth-at-cste-conference/</id>
      <published>2022-06-09T00:00:00+00:00</published>
      <author>
        <name>Shannon Sandall</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2022/06/booth-at-cste-conference/david-barajas-RIQyCVb5IQY-unsplash.webp&#34; alt=&#34;Divided interstate highway in lush green trees and fields&#34;&gt;
&lt;a href=&#34;https://unsplash.com/photos/RIQyCVb5IQY&#34;&gt;Photo by David Barajas&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;converging-on-kentucky&#34;&gt;Converging on Kentucky&lt;/h3&gt;
&lt;p&gt;We are excited to announce that End Point will be attending the &lt;a href=&#34;https://www.csteconference.org/&#34;&gt;CSTE (Council of State and Territorial Epidemiologists) conference&lt;/a&gt; in less than two weeks!&lt;/p&gt;
&lt;p&gt;We will be running a booth during the 3-day conference in Louisville, Kentucky from Monday, June 20 through Wednesday, June 22, 2022. Our crew is scheduled to include Steve Yoman, Linda King, Ben Goldstein, and me.&lt;/p&gt;
&lt;p&gt;Please come visit us in booth #35 to learn more about the EpiTrax Disease Surveillance System and EMSA (Electronic Message Staging Area). Now is the time for public health entities to turn to modern systems to perform disease surveillance, automate the ingestion of electronic laboratory records (ELRs) and electronic case reports (eCRs), report to the CDC through NMI reporting methods, track outbreaks, perform contact management, and do it all with a highly configurable system.&lt;/p&gt;
&lt;p&gt;Our booth will feature a VisionPort Mini to showcase EpiTrax and EMSA! &lt;a href=&#34;https://www.visionport.com/&#34;&gt;VisionPort&lt;/a&gt; is our product combining hardware and software to give organizations the ability to create dynamic, shared immersive multimedia experiences. We are delighted when we have opportunities like this to use VisionPort to inform conference attendees about our own offerings such as EpiTrax and EMSA.&lt;/p&gt;
&lt;p&gt;We will be happy to demonstrate EpiTrax to you there. Here is a preview screenshot of the application&amp;rsquo;s disease outbreaks list view:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/images/epitrax-outbreaks-demo.webp&#34; alt=&#34;Screenshot of EpiTrax web application showing a list of disease outbreaks&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;cste&#34;&gt;CSTE&lt;/h3&gt;
&lt;p&gt;What is CSTE? The &lt;a href=&#34;https://www.cste.org/&#34;&gt;Council of State and Territorial Epidemiologists&lt;/a&gt; is an organization that works to advance public health policy and epidemiologic capacity. They also provide information, education, and developmental support of practicing epidemiologists in a wide range of areas as well as expertise for program and surveillance efforts.&lt;/p&gt;
&lt;p&gt;Here are some of the conference sessions we plan to attend:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Monday, 2:00–3:15 PM:&lt;/strong&gt; In-Person Concurrent Breakout Sessions: Surveillance / Informatics I: Not Your Grandma’s Old-Fashioned: Data Modernization&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monday, 5:45–6:30 PM:&lt;/strong&gt; Virtual Concurrent Roundtable Sessions / Networking Surveillance / Informatics II: Electronic Case Reporting and Public Health Agencies—Needs and Directions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tuesday, 8:45–10:00 AM:&lt;/strong&gt; In-Person Concurrent Breakout Sessions: Surveillance / Informatics I: Taking off the Blinders: Innovative Methods for Detection and Surveillance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tuesday, 5:45–6:30 PM:&lt;/strong&gt; In-Person Concurrent Roundtable Sessions / Networking: Surveillance / Informatics I: CSTE National ELR Workgroup Meet and Greet&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wednesday, 7:30–8:15 AM:&lt;/strong&gt; In-Person Concurrent Roundtable Sessions / Networking: Surveillance Informatics I: National Notifiable Disease Surveillance System (NNDSS): A Comprehensive Review&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Come see what End Point and EpiTrax can do for you! We would love to meet with you in person, a privilege we don&amp;rsquo;t take for granted these days.&lt;/p&gt;
&lt;p&gt;Or if you can&amp;rsquo;t make the conference, &lt;a href=&#34;/contact/&#34;&gt;contact us&lt;/a&gt; here online.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Data Reporting with EpiTrax</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2022/02/data-reporting-with-epitrax/"/>
      <id>https://www.endpointdev.com/blog/2022/02/data-reporting-with-epitrax/</id>
      <published>2022-02-16T00:00:00+00:00</published>
      <author>
        <name>Shannon Sandall</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2022/02/data-reporting-with-epitrax/20220107_002143-sm.webp&#34; alt=&#34;Sunset view from mountain height overlooking valley with city, lake, mountains with some snow, below yellow horizon and orange clouds under a blue sky&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Jon Jensen --&gt;
&lt;h3 id=&#34;early-covid-19-form-building-in-kansas&#34;&gt;Early COVID-19 form-building in Kansas&lt;/h3&gt;
&lt;p&gt;In March of 2020, many states struggled with disease surveillance systems that were not ready for the COVID-19 pandemic. States were forced to wait lengthy periods for their vendors or systems administrators to stand up customized forms for COVID-19 investigations.&lt;/p&gt;
&lt;p&gt;State of Kansas informatics staff were able to configure their form within a matter of hours. When the first COVID-19 records came rolling in, the state was ready to go. The Kansas Department of Health and Environment (KDHE) was using EpiTrax, a National Electronic Disease Surveillance System (NEDSS) compliant application created by the state of Utah.&lt;/p&gt;
&lt;p&gt;EpiTrax contains a powerful form-building utility that was easily customizable, allowing jurisdictional users to create forms for investigation and reporting purposes. Users could configure questions and value sets based on configurable lists, cutting down on free-text entries and ensuring data quality. Forms could be attached automatically or manually and assigned to specified agencies and conditions.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2022/02/data-reporting-with-epitrax/screenshot1.webp&#34; alt=&#34;Screenshot of form builder on Form Attributes tab with checkbox lists for Agencies and Conditions&#34;&gt;&lt;br&gt;
Screenshot of the form builder&lt;/p&gt;
&lt;h3 id=&#34;december-2021-updates&#34;&gt;December 2021 updates&lt;/h3&gt;
&lt;p&gt;Flash forward to December 2021. State of Utah developers rolled out an update to the EpiTrax form builder utility. All the previous version features, such as quick configurability and use of lists, remain, with additions to make investigators’ and informaticians’ lives easier. While the old form module was configurable, it did have room for improvement.&lt;/p&gt;
&lt;p&gt;The latest updates include question banks and value set banks that can be used across disease forms. This option allows for consistency across all forms and in reporting and analyzing data. State jurisdictions use system forms and core fields to pull data for CDC reporting purposes. The CDC NMI message mapping guides (MMGs) are the new generation of data transfer. These MMGs often require repeating fields, one option now available in the EpiTrax form builder.&lt;/p&gt;
&lt;p&gt;Users can configure forms based on the guide formats. Forms can be shared across conditions, aiding in the use of forms across comorbidities. The new form builder allows users to relate fields to existing core fields and sections. This allows the system to be more flexible and aids in creating a better flow in the user interface. The question formats accommodate many data types including address, phone and dates.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2022/02/data-reporting-with-epitrax/screenshot2.webp&#34; alt=&#34;Screenshot of select box drop-down showing widget type options&#34;&gt;&lt;br&gt;
Screenshot of the field type selector&lt;/p&gt;
&lt;h3 id=&#34;utahs-experience&#34;&gt;Utah&amp;rsquo;s experience&lt;/h3&gt;
&lt;p&gt;End Point staff discussed the new form builder with the Utah Department of Health’s (UDOH) Health Informatics Program Manager, Rachelle Boulton. Rachelle related that UDOH was able to add form fields and configure those fields in the EpiTrax NMI Module within one day when the CDC recently released version 1.1 of their COVID-19 MMG. They reached out to the CDC on December 13th to announce their readiness and were the first state to onboard on December 29th.&lt;/p&gt;
&lt;p&gt;She attributed the quick turnaround to the new form builder’s ease of use and to their use of the NMI Module. Rachelle said, “The form builder gives us the opportunity to collect data for CDC reporting requirements and allows us to make changes quickly and send data out quickly.”&lt;/p&gt;
&lt;p&gt;When asked what she likes most about the new form builder, Rachelle stated that she appreciates the new question and answer banks and their ability to quickly and efficiently create new forms that are appealing on the user interface.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2022/02/data-reporting-with-epitrax/screenshot3.webp&#34; alt=&#34;Screenshot of Manage Questions page showing value sets tab and list of values that can be used in form responses&#34;&gt;&lt;br&gt;
Screenshot of the question manager&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;End Point is collaborating with our current clients to migrate data from the old form builder to the new. We are excited to help them use the new functionality.&lt;/p&gt;
&lt;p&gt;Along with this effort, we hope to build a form repository for future clients using the new form enhancements which will allow users to quickly onboard for CDC MMG reporting. These new forms would accommodate any needed state workflow changes or additions and would allow states to implement EpiTrax in a timelier manner.&lt;/p&gt;
&lt;p&gt;When asked if she had anything else to add, Rachelle said, “I really like that we try to make EpiTrax not just a surveillance system, but a change management system. We embed these changes in the workflow to make users’ lives easier.”&lt;/p&gt;
&lt;p&gt;We at End Point agree with Rachelle. We look forward to the future of EpiTrax and what we can do to help it continue to improve moving forward.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>How to use regular expression group quantifiers in PostgreSQL</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2022/01/regex-group-quantifiers-postgresql/"/>
      <id>https://www.endpointdev.com/blog/2022/01/regex-group-quantifiers-postgresql/</id>
      <published>2022-01-27T00:00:00+00:00</published>
      <author>
        <name>Selvakumar Arumugam</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2022/01/regex-group-quantifiers-postgresql/20220123_222150.webp&#34; alt=&#34;Side of brick building with windows and protruding roof, tiered shrubs in foreground, with a small corner of blue sky, clouds, and snowy mountaintop&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Jon Jensen --&gt;
&lt;p&gt;I recently encountered a situation where it was necessary to extract address content from text in HL7 V2 format from a PostgreSQL table&amp;rsquo;s column. The following example is representative:&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;||121212^^^2^ID 1|676767||SELVA^KUMAR^^^^|19480203|M||B||123456 SAMPLE ROAD^^New York City^NY^12345^USA^H^^New York||123456-7890|||M|NON|4000|&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In order to manipulate our example, the address section needs to be extracted from the HL7 V2 message PID segment for patient demographic information. The segments have delimiters for fields (&lt;code&gt;|&lt;/code&gt;), components (&lt;code&gt;^&lt;/code&gt;), subcomponents (&lt;code&gt;&amp;amp;&lt;/code&gt;) and repetition (&lt;code&gt;~&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Our example has only fields and components delimited by pipe (&lt;code&gt;|&lt;/code&gt;) and caret (&lt;code&gt;^&lt;/code&gt;). The address contains nine components delimited by &lt;code&gt;^&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I hoped to do this by applying a regular expression (regex) because the address is in a standard format that regex can match with alphanumeric and caret repetition.&lt;/p&gt;
&lt;p&gt;Here is my journey figuring out how to match the data I wanted.&lt;/p&gt;
&lt;h3 id=&#34;regex-pattern-in-grep&#34;&gt;Regex pattern in grep&lt;/h3&gt;
&lt;p&gt;As a test, I got this regex working with the &lt;code&gt;grep&lt;/code&gt; command, which successfully extracts the address section from the content:&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;$ &lt;span style=&#34;color:#369&#34;&gt;content&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;||121212^^^2^ID 1|676767||SELVA^KUMAR^^^^|19480203|M||B||123456 SAMPLE ROAD^^New York City^NY^12345^USA^H^^New York||123456-7890|||M|NON|4000|&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:#038&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$content&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt; | grep -Eo &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;([A-Za-z0-9 #&amp;#39;.,/-]*\^){8}[A-Za-z0-9 ]*&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:#00d;font-weight:bold&#34;&gt;123456&lt;/span&gt; SAMPLE ROAD^^New York City^NY^12345^USA^H^^New York&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;postgresql-regex-attempt&#34;&gt;PostgreSQL regex attempt&lt;/h3&gt;
&lt;p&gt;The PostgreSQL &lt;code&gt;regexp_matches&lt;/code&gt; function supports extraction by pattern-matching data from the content. But when I used the same regex pattern with the &lt;code&gt;regexp_matches&lt;/code&gt; function, instead of all eight groups, only the eighth value was returned:&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-postgres&#34; data-lang=&#34;postgres&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=# &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; regexp_matches(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;||121212^^^2^ID 1|676767||SELVA^KUMAR^^^^|19480203|M||B||123456 SAMPLE ROAD^^New York City^NY^12345^USA^H^^New York||123456-7890|||M|NON|4000|&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;([A-Za-z0-9 #&amp;#39;&amp;#39;.,/-]*\^){8}[A-Za-z0-9 ]*&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;g&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; regexp_matches 
&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&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&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;row&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;More generally, our query is returning the &lt;em&gt;N&lt;/em&gt;th matching group instead of returning all matching groups until the &lt;em&gt;N&lt;/em&gt;th regex group. So if we try to fetch the text matching with 3 groups, the quantifier will return the third field of all match sections instead of the third group itself.&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-postgres&#34; data-lang=&#34;postgres&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=# &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; regexp_matches(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;||121212^^^2^ID 1|676767||SELVA^KUMAR^^^^|19480203|M||B||123456 SAMPLE ROAD^^New York City^NY^12345^USA^H^^New York||123456-7890|||M|NON|4000|&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;([A-Za-z0-9 #&amp;#39;&amp;#39;.,/-]*\^){3}[A-Za-z0-9 ]*&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;g&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   regexp_matches   
&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&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&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:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;New York City^&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {USA^}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;rows&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;plperl-function&#34;&gt;PL/Perl function&lt;/h3&gt;
&lt;p&gt;Since that doesn’t satisfy our requirements, I tried using a Perl regex through my own PL/Perl function, and got the expected answer:&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-postgres&#34; data-lang=&#34;postgres&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=# &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;OR&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;REPLACE&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FUNCTION&lt;/span&gt; perl_regexp_matches (&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;IN&lt;/span&gt; str &lt;span style=&#34;color:#038&#34;&gt;text&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;IN&lt;/span&gt; pattern &lt;span style=&#34;color:#038&#34;&gt;text&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;RETURNS&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;text&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;AS&lt;/span&gt; &lt;span style=&#34;color:#d20;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:#d20;background-color:#fff0f0&#34;&gt;    my ($input, $pattern) = @_;
&lt;/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;    $output = [$input =~ m/($pattern)/];
&lt;/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;    return $output-&amp;gt;[0]
&lt;/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;$$&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;LANGUAGE&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;plperl&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;SELECT&lt;/span&gt; perl_regexp_matches(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;||121212^^^2^ID 1|676767||SELVA^KUMAR^^^^|19480203|M||B||123456 SAMPLE ROAD^^New York City^NY^12345^USA^H^^New York||123456-7890|||M|NON|4000|&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;([A-Za-z0-9 #&amp;#39;&amp;#39;.,/-]*\^){8}[A-Za-z0-9 ]*&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    perl_regexp_matches
&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&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:#00d;font-weight:bold&#34;&gt;123456&lt;/span&gt; SAMPLE ROAD^^New York City^NY^&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;12345&lt;/span&gt;^USA^H^^New York
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;row&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But I researched further for a simple solution to achieve the result without using a custom function and the PL/Perl extension.&lt;/p&gt;
&lt;h3 id=&#34;postgresql-regex-solution&#34;&gt;PostgreSQL regex solution&lt;/h3&gt;
&lt;p&gt;In Postgres regex syntax, parentheses &lt;code&gt;()&lt;/code&gt; create a numbered capture group which leads to returning the contained matching results.&lt;/p&gt;
&lt;p&gt;To get the entire matching data, the regex should have a question mark and a colon (&lt;code&gt;?:&lt;/code&gt;) added at the beginning of the regex pattern to create a non-capturing group. Then because no group is capturing, instead the complete match is returned:&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-postgres&#34; data-lang=&#34;postgres&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; regexp_matches(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;||121212^^^2^ID 1|676767||SELVA^KUMAR^^^^|19480203|M||B||123456 SAMPLE ROAD^^New York City^NY^12345^USA^H^^New York||123456-7890|||M|NON|4000|&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;(?:[A-Za-z0-9 #&amp;#39;&amp;#39;.,/-]*\^){8}[A-Za-z0-9 ]*&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                         regexp_matches                         
&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&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:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;123456 SAMPLE ROAD^^New York City^NY^12345^USA^H^^New York&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:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;row&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That turns out to be what was happening with my PL/Perl function where &lt;code&gt;m/($pattern)/&lt;/code&gt; captures the entire match, and what &lt;code&gt;grep&lt;/code&gt; was doing because of its option &lt;code&gt;-o&lt;/code&gt; or &lt;code&gt;--only-matching&lt;/code&gt;, which prints the matching part of the lines rather than its default of printing the entire line.&lt;/p&gt;
&lt;p&gt;And we can also use the Postgres function &lt;code&gt;substring&lt;/code&gt; to return the bare text itself instead of arrays as &lt;code&gt;regexp_matches&lt;/code&gt; does:&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-postgres&#34; data-lang=&#34;postgres&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=# &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;substring&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;||121212^^^2^ID 1|676767||SELVA^KUMAR^^^^|19480203|M||B||123456 SAMPLE ROAD^^New York City^NY^12345^USA^H^^New York||123456-7890|||M|NON|4000|&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;(?:[A-Za-z0-9 #&amp;#39;&amp;#39;.,/-]*\^){8}[A-Za-z0-9 ]*&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;substring&lt;/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&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:#00d;font-weight:bold&#34;&gt;123456&lt;/span&gt; SAMPLE ROAD^^New York City^NY^&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;12345&lt;/span&gt;^USA^H^^New York
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;row&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;reference&#34;&gt;Reference&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.hl7.org/about/&#34;&gt;HL7 International website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.postgresql.org/docs/current/functions-matching.html#FUNCTIONS-POSIX-REGEXP&#34;&gt;PostgreSQL POSIX regular expressions documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
    <entry>
      <title>EMSA: Electronic Messaging Staging Area</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2020/10/electronic-messaging-staging-area/"/>
      <id>https://www.endpointdev.com/blog/2020/10/electronic-messaging-staging-area/</id>
      <published>2020-10-30T00:00:00+00:00</published>
      <author>
        <name>Elizabeth Garrett Christensen</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2020/10/electronic-messaging-staging-area/emsa-banner.jpg&#34; alt=&#34;Sunset&#34;&gt;
&lt;a href=&#34;https://flic.kr/p/pnRYaf&#34;&gt;Photo&lt;/a&gt; by &lt;a href=&#34;https://flic.kr/ps/2bXFPr&#34;&gt;Lee Roberts&lt;/a&gt;, &lt;a href=&#34;https://creativecommons.org/licenses/by-sa/2.0/&#34;&gt;CC BY-SA 2.0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;End Point has been involved with developing disease surveillance software for over a decade. One component of that work is EMSA, short for “Electronic Messaging Staging Area”.&lt;/p&gt;
&lt;p&gt;The EMSA system we’re currently using was developed by a consortium of states led by Utah, Kansas, and Nevada. It is a PHP web application and can be hosted in the cloud or on-premises as you would any other PHP application.&lt;/p&gt;
&lt;h3 id=&#34;emsa&#34;&gt;EMSA:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Is an ingest system for HL7 or CSV-formatted lab reports from doctor offices, labs, and other official reporting groups.&lt;/li&gt;
&lt;li&gt;Allows exporting XML output to your disease surveillance system.&lt;/li&gt;
&lt;li&gt;Is a web console for managing messages.&lt;/li&gt;
&lt;li&gt;Allows you to see messages that are malformed.&lt;/li&gt;
&lt;li&gt;Has configurable rules for disease types and message routing; some messages may go directly into a surveillance system while others may be stored for later.&lt;/li&gt;
&lt;li&gt;Has configurable “automated workflows” to validate message information and perform tasks.&lt;/li&gt;
&lt;li&gt;Can be connected to a BI (Business Intelligence) tool for reporting, or the database can be queried directly.&lt;/li&gt;
&lt;li&gt;Works with integration packages like Rhapsody to bring in data from other systems.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;End Point has also made custom modifications to EMSA allowing address validation for incoming messages.&lt;/p&gt;
&lt;p&gt;EMSA can be deployed along with EpiTrax, the open source tracking system, or as a standalone application connected to a different disease surveillance system.&lt;/p&gt;
&lt;h3 id=&#34;benefits-of-emsa&#34;&gt;Benefits of EMSA&lt;/h3&gt;
&lt;p&gt;Aside from all the features mentioned above, EMSA as an open-source solution brings other benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reduced cost: Other than development and consulting to help set it up, there are no ongoing licensing costs.&lt;/li&gt;
&lt;li&gt;Designed to work as part of the open-source EpiTrax disease surveillance system.&lt;/li&gt;
&lt;li&gt;Participating in the open source community that is growing in the healthcare industry.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;help-is-available&#34;&gt;Help is available!&lt;/h3&gt;
&lt;p&gt;Interested in talking to us more about EMSA for your disease tracking? &lt;a href=&#34;/contact/&#34;&gt;Reach out today.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;references&#34;&gt;References&lt;/h3&gt;
&lt;p&gt;Emily Roberts, Rachelle Boulton, Josh Ridderhoff, Theron Jeppson. “Automated Processing of Electronic Data for Disease Surveillance.” &lt;em&gt;Online Journal of Public Health Informatics, 10(1):e2, May 22, 2018.&lt;/em&gt; &lt;a href=&#34;https://doi.org/10.5210/ojphi.v10i1.8903&#34;&gt;https://doi.org/10.5210/ojphi.v10i1.8903&lt;/a&gt;&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>COVID-19 Support for the Kansas Department of Health and Environment</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2020/09/covid-19-support-kansas-dept-health/"/>
      <id>https://www.endpointdev.com/blog/2020/09/covid-19-support-kansas-dept-health/</id>
      <published>2020-09-14T00:00:00+00:00</published>
      <author>
        <name>Steve Yoman</name>
      </author>
      <content type="html">
        &lt;h3 id=&#34;kansass-existing-epitrax-system&#34;&gt;Kansas’s existing EpiTrax system&lt;/h3&gt;
&lt;p&gt;End Point has worked on Kansas’s disease surveillance systems since 2011. In 2018 we migrated them from their legacy TriSano application to the open source EpiTrax surveillance system created by Utah’s Department of Health. The new EpiTrax system had been in full production for about eight months when COVID-19 cases started to grow in the United States.&lt;/p&gt;
&lt;h3 id=&#34;covid-19-help-needed&#34;&gt;COVID-19: Help needed&lt;/h3&gt;
&lt;p&gt;In March 2020, the Director of Surveillance Systems at the Kansas Department of Health and Environment (KDHE) asked us at End Point to create a web-based portal where labs, hospitals, and ad-hoc testing locations could enter COVID-19 test data. While systems existed for gathering data from labs and hospitals, they needed a way to quickly gather data from the many new and atypical sites collecting COVID-19 test information.&lt;/p&gt;
&lt;h3 id=&#34;our-approach&#34;&gt;Our approach&lt;/h3&gt;
&lt;p&gt;Since the portal was intended for people who were unfamiliar with the existing EpiTrax application, we were able to create a new design that was simple and direct, unconstrained by other applications. It required a self-registration function so users could access the system quickly and without administrative overhead, and users needed to understand how to use it without extensive training.&lt;/p&gt;
&lt;p&gt;We at End Point agreed to create the portal and dashboard for test results reporters immediately, while planning for later development of additional administrative functions. We used Ruby on Rails and Vue.js to build the portal due to their usefulness for rapid development. The Vue.js front-end JavaScript framework allowed us to quickly put together the portal UI and integrate it with the Rails back-end web services.&lt;/p&gt;
&lt;p&gt;Once approved, our team got to work setting up the environment, developing the portal application, and rigorously testing it.&lt;/p&gt;
&lt;p&gt;Here are some screenshots of the application:&lt;/p&gt;
&lt;h3 id=&#34;portal-home-page&#34;&gt;Portal home page&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/09/covid-19-support-kansas-dept-health/Home-Screen.jpg&#34; alt=&#34;Kansas Reportable Disease Portal home page&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;user-registration-page&#34;&gt;User registration page&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/09/covid-19-support-kansas-dept-health/newuser.png&#34; alt=&#34;Create New User Account page&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;dashboard&#34;&gt;Dashboard&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/09/covid-19-support-kansas-dept-health/dashboard.jpg&#34; alt=&#34;Dashboard for searching and browsing cases&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;reporters-entry-screens&#34;&gt;Reporters’ entry screens&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/09/covid-19-support-kansas-dept-health/Reporter-Data-Entry.jpg&#34; alt=&#34;Forms collecting information about reporter and patient&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/09/covid-19-support-kansas-dept-health/form-part-2.png&#34; alt=&#34;Forms collecting information about disease, speciment, and testing results&#34;&gt;&lt;/p&gt;
&lt;p&gt;The portal was launched on April 30.&lt;/p&gt;
&lt;h3 id=&#34;contact-tracers-support&#34;&gt;Contact tracers support&lt;/h3&gt;
&lt;p&gt;After the EpiTrax portal for COVID-19 was up and running, Kansas made urgent plans to hire 400 contact tracers. We updated the EpiTrax portal to accommodate this new type of user, showing contact tracers only the data they are authorized to view, while providing them the ability to make limited contact record updates and to create tasks. The project is ongoing, and eventually will be used for all diseases.&lt;/p&gt;
&lt;h3 id=&#34;epitrax-for-missouri&#34;&gt;EpiTrax for Missouri&lt;/h3&gt;
&lt;p&gt;Late this Spring, after learning of Kansas’s use of the EpiTrax platform and the powerful capabilities that it provides to the Kansas public health system, the State of Missouri reached out to us at End Point to request their own EpiTrax implementation. End Point and Missouri quickly came to agreement, and since July we have been working together build out a full production EpiTrax surveillance system for them.&lt;/p&gt;
&lt;h3 id=&#34;contact-us&#34;&gt;Contact us!&lt;/h3&gt;
&lt;p&gt;To discuss an EpiTrax project, &lt;a href=&#34;/contact/&#34;&gt;contact&lt;/a&gt; us. Our expert team is ready to help you meet your requirements.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Consolidating Multiple SFTP Accounts Into One Master Account</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2020/03/consolidating-multiple-sftp-accounts/"/>
      <id>https://www.endpointdev.com/blog/2020/03/consolidating-multiple-sftp-accounts/</id>
      <published>2020-03-16T00:00:00+00:00</published>
      <author>
        <name>Selvakumar Arumugam</name>
      </author>
      <content type="html">
        &lt;img src=&#34;/blog/2020/03/consolidating-multiple-sftp-accounts/image-0.jpg&#34; alt=&#34;merging roads&#34; /&gt;
&lt;p&gt;&lt;a href=&#34;https://unsplash.com/photos/kzSNNqqS3Qs&#34;&gt;Photo&lt;/a&gt; by &lt;a href=&#34;https://unsplash.com/@dmey503&#34;&gt;Dan Meyers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Recently, a client implemented a data-intensive workflow to generate various reports and insights from a list of facilities as part of an EpiTrax installation. Because a significant portion of these files contain sensitive healthcare data, they needed to strictly comply with HIPAA. Optimally, facilities should be able to transfer files securely and exclusively to our server. One of the best methods of achieving this is to create individual SSH File Transfer Protocol (SFTP) accounts for each source.&lt;/p&gt;
&lt;h3 id=&#34;sftp-account&#34;&gt;SFTP account&lt;/h3&gt;
&lt;p&gt;Private SFTP accounts were established for each facility and the data was received at a designated path. At these individual points of contact, a third-party application picks up the data and processes further into the pipeline. The following demonstrates how SFTP accounts are developed and configured:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a user group for SFTP accounts:&lt;/li&gt;
&lt;/ul&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;$ addgroup sftpusers&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Configure the following settings in sshd_config (this enables an SFTP account and sets the default location as the home path):&lt;/li&gt;
&lt;/ul&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;$ vi /etc/ssh/sshd_config
&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;# override default of no subsystems&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Subsystem       sftp    internal-sftp...
&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;Match Group sftpusers
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ChrootDirectory /home/%u
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    AllowTCPForwarding no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    X11Forwarding no
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ForceCommand internal-sftp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Restart SSH server to apply changes:&lt;/li&gt;
&lt;/ul&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;$ systemctl restart ssh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Create an SFTP user account for a facility and place in a folder on the home path to receive data:&lt;/li&gt;
&lt;/ul&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;&lt;span style=&#34;color:#888&#34;&gt;# set new user name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;sftpuser&lt;/span&gt;=the-new-username
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;useradd &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;usermod -g sftpusers -s /usr/sbin/nologin &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;/INPUT_PATH/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R root:root /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;mount-multiple-accounts-to-one-account&#34;&gt;Mount multiple accounts to one account&lt;/h3&gt;
&lt;p&gt;The goal here is to point the data from many facilities to one location, but using a single account and path for multiple sites’ data could result in a breach of security and/​or privacy. Mounting the receiving path of a facility’s data onto a single master account and then to a “mount point” with a unique facility name takes care of this issue. The process next consolidates files from individual paths on a master account in one place where the application picks up messages for further processing.&lt;/p&gt;
&lt;p&gt;The SFTP accounts and the master account should be attached to the same group. This will permit individual accounts to write on the master account-mounted path. In turn, the master account can read files from the same location. This location now has administrative rights for both the SFTP user the group. Group permission of the mounted folder is set to sftpgroup and user permission is set to the facility account.&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;&lt;span style=&#34;color:#888&#34;&gt;# create master user account&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ adduser master
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ passwd master
&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;# Add master user to sftpgroup group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;usermod -a -G sftpgroup master
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;getent group sftpgroup
&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;# MOUNT_PATH and sub folders&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /home/master/MOUNT_PATH/{Input,Pickup,Backup,Archive}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R master:master /home/master/MOUNT_PATH&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We wrote a script to automate the process of creating an SFTP account, mounting it at the master account path, and adding fstab entries to save the mount in the case of a reboot. The script not only saves time, but also avoids human error when creating accounts for all facilities.&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;&lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;#!/bin/bash
&lt;/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;&lt;/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_sftp_account.sh sftpfacilityone FACILITY_ONE&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:#369&#34;&gt;sftpuser&lt;/span&gt;=&lt;span style=&#34;color:#369&#34;&gt;$1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;facility_name&lt;/span&gt;=&lt;span style=&#34;color:#369&#34;&gt;$2&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;# Create SFTP account and add to sftpgroup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;useradd &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;usermod -g sftpusers -s /usr/sbin/nologin &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;usermod -a -G sftpgroup &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;/INPUT_PATH
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown root:root /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&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;# Create path specific to facility in master account Input folder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /home/master/MOUNT_PATH/Input/&lt;span style=&#34;color:#369&#34;&gt;$facility_name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;:sftpgroup /home/master/MOUNT_PATH/Input/&lt;span style=&#34;color:#369&#34;&gt;$facility_name&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;# Mount sftp account into master account and set permissions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mount --bind /home/master/MOUNT_PATH/Input/&lt;span style=&#34;color:#369&#34;&gt;$facility_name&lt;/span&gt; /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;/INPUT_PATH
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chown -R &lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;:sftpgroup /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;/INPUT_PATH
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod &lt;span style=&#34;color:#369&#34;&gt;g&lt;/span&gt;=rwxs /home/&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;/INPUT_PATH
&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;# Add fstab entry to persist and mount on reboot&lt;/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;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/home/master/MOUNT_PATH/Input/&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$facility_name&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; /home/&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/INPUT_PATH none bind 0 0&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/fstab
&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;echo&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Created user &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$sftpuser&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; at &lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$facility_name&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; mount point successfully&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;files-at-one-location&#34;&gt;Files at one location&lt;/h3&gt;
&lt;p&gt;Now, data files from facilities are available at individual folders under MOUNT_PATH/Input on the master account. This enables third-party applications to pick up files in a straightforward way to proceed with further processing. It also helps our client access the files for review from the master account easily without navigating into each separate account.&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;Mounting multiple SFTP accounts onto one master account turns out to be an efficient and beneficial method of consolidating data. Both safe and secure, running separate SFTP accounts establishes an exclusive private link between facilities and servers. The master account has the unique ability to access files belonging to each facility in order to process the data further.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: In order to avoid broken mounts, check the status by using the command &lt;code&gt;mount -fav&lt;/code&gt;. Problems with mount configurations can cause broken mounts after rebooting the server.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Cooking with CAS</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2020/03/cooking-with-cas/"/>
      <id>https://www.endpointdev.com/blog/2020/03/cooking-with-cas/</id>
      <published>2020-03-10T00:00:00+00:00</published>
      <author>
        <name>Josh Tolley</name>
      </author>
      <content type="html">
        &lt;img src=&#34;/blog/2020/03/cooking-with-cas/4696900602_77582d1d5d_c.jpg&#34; alt=&#34;Laptop on a desk showing a web browser open to a login form, with a Post-It note saying &#39;ADMIN / ADMIN&#39; attached to the screen&#34; /&gt;
&lt;p&gt;Photo by Flickr user &lt;a href=&#34;http://web.archive.org/web/20190305093832/https://www.flickr.com/photos/reidrac/&#34;&gt;reidrac&lt;/a&gt;, licensed
under &lt;a href=&#34;https://creativecommons.org/licenses/by-sa/2.0/&#34;&gt;CC BY-SA 2.0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;One of our customers asked us to host a new suite of web-based applications for them and to protect them with a single sign-on (SSO) solution. Ok, easy enough;
these applications were in fact designed with a particular SSO system in mind already, but our situation required a different one, and we eventually chose
Apereo’s open source &lt;a href=&#34;https://www.apereo.org/projects/cas&#34;&gt;Central Authentication Server project&lt;/a&gt;, or CAS. I’d like to describe the conversion process we went
through.&lt;/p&gt;
&lt;h3 id=&#34;the-ingredients&#34;&gt;The ingredients&lt;/h3&gt;
&lt;p&gt;Our customer’s application suite included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The principal Java application using &lt;a href=&#34;https://docs.oracle.com/javase/7/docs/technotes/guides/security/jaas/JAASRefGuide.html&#34;&gt;JAAS authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Another Java application based on &lt;a href=&#34;https://spring.io/projects/spring-security&#34;&gt;Spring Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A pair of PHP applications&lt;/li&gt;
&lt;li&gt;A few automated tasks that needed to authenticate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The original SSO system sets a header on each request, identifying an authenticated user. This requires a gateway system to sanitize request headers to ensure
malicious users cannot forge a header themselves. It also requires each application inspect request headers and respond appropriately.&lt;/p&gt;
&lt;p&gt;CAS is a bit more complex: applications redirect unauthenticated requests to a CAS server, which authenticates the user through any of various configurable
methods. The CAS server then redirects the user back to the original application with a parameter called a “Service Ticket”, a seemingly random number
identifying an individual authentication request. The original application contacts the CAS server directly to validate the service ticket and to collect
information to identify the user. It can then establish a session for that user, and proceed normally.&lt;/p&gt;
&lt;p&gt;To CAS-enable an application, we incorporate one of the CAS &lt;a href=&#34;https://apereo.github.io/cas/6.1.x/integration/CAS-Clients.html#build-your-own-cas-client&#34;&gt;client
libraries&lt;/a&gt;, which exist for various languages. In fact we won’t use
the Java client directly, but rather we’ll incorporate components that extend it. When evaluating CAS, I was a bit concerned by what appeared to be a
surprisingly limited selection of actively supported client libraries, and of course your results may vary, but we found software to meet our own needs without
too much difficulty.&lt;/p&gt;
&lt;h3 id=&#34;configuring-wildfly-authentication&#34;&gt;Configuring Wildfly Authentication&lt;/h3&gt;
&lt;p&gt;The most important application in the suite depends on the JAAS-based security subsystem of the &lt;a href=&#34;https://www.wildfly.org/&#34;&gt;Wildfly application server&lt;/a&gt; it’s
deployed to. Originally it used a custom &lt;a href=&#34;https://docs.oracle.com/javase/7/docs/api/javax/security/auth/spi/LoginModule.html&#34;&gt;LoginModule&lt;/a&gt; that inspected
request headers to find the ID of the authenticated user. Our first task was to configure our proxy server to remove this header from every request. We planned
to disable the old authentication system entirely, of course, but this change ensured that even if we mistakenly left it enabled somewhere, malicious users
couldn’t exploit it for access.&lt;/p&gt;
&lt;p&gt;This application uses a declarative security policy: the deployment descriptor identifies a set of user roles, and another set of “security constraints”. Each
security constraint describes one or more URL patterns used in the application, and the set of user roles allowed to access URLs matching those patterns. Here
are two examples:&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:#888&#34;&gt;&amp;lt;!-- clients --&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;security-constraint&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;web-resource-collection&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;web-resource-name&amp;gt;&lt;/span&gt;Secure Area&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/web-resource-name&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;url-pattern&amp;gt;&lt;/span&gt;/views/clients/*&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/url-pattern&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;url-pattern&amp;gt;&lt;/span&gt;/client/edit/*&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/url-pattern&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;url-pattern&amp;gt;&lt;/span&gt;/client/edit_tree/*&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/url-pattern&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;url-pattern&amp;gt;&lt;/span&gt;/client/view/*&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/url-pattern&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;url-pattern&amp;gt;&lt;/span&gt;/client/view/id/*&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/url-pattern&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;/web-resource-collection&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;auth-constraint&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;role-name&amp;gt;&lt;/span&gt;client_role&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/role-name&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;/auth-constraint&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;/security-constraint&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:#888&#34;&gt;&amp;lt;!-- places --&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;security-constraint&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;web-resource-collection&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;web-resource-name&amp;gt;&lt;/span&gt;Secure Area&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/web-resource-name&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;url-pattern&amp;gt;&lt;/span&gt;/views/places/*&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/url-pattern&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;/web-resource-collection&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;auth-constraint&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;role-name&amp;gt;&lt;/span&gt;manage_places&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/role-name&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;/auth-constraint&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;/security-constraint&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We installed the &lt;a href=&#34;https://github.com/soulwing/cas-extension&#34;&gt;cas-extension library&lt;/a&gt; in our Wildfly server to handle the CAS protocol. When an unauthenticated
user attempts to access a URL matching a pattern in one of the application’s security constraints, the CAS extension automatically intercepts control and
redirects the user to the CAS server. Assuming the user authenticates successfully, our application will receive another request with a service ticket
parameter. The cas-extension intercepts this request as well, validates the service ticket, and creates an “identity assertion”, which it sends to the Wildfly
security system. Wildfly’s role mapper queries a database to find the user’s roles, after which the authentication process is complete.&lt;/p&gt;
&lt;p&gt;Configuration of the cas-extension begins with a CAS profile, a combination of the URL of the CAS server and the URL of the service the extension should
protect.&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:#b06;font-weight:bold&#34;&gt;&amp;lt;subsystem&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;xmlns=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;urn:soulwing.org:cas:1.0&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;cas-profile&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;default&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;service-url=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;https://our.application.server/application&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;server-url=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;https://our.cas.server&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;/subsystem&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This tells the extension where to send authentication requests, where to listen for requests returning from the CAS server, and where to validate service
tickets. Next we need to validate that identity assertion, and figure out what roles belong to the user. This happens in a &lt;a href=&#34;https://docs.wildfly.org/14/Admin_Guide.html#security-domains&#34;&gt;Wildfly security
domain&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-xml&#34; data-lang=&#34;xml&#34;&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;security-domain&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;MySecurityDomain&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;authentication&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;login-module&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;IdentityAssertion&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;code=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;org.soulwing.cas.jaas.IdentityAssertionLoginModule&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;flag=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;required&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;module=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;org.soulwing.cas&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;/authentication&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;mapping&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;mapping-module&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;code=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;DatabaseRoles&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;role&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;module-option&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;dsJndiName&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;java:/comp/env/jdbc/databaseConnection&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;module-option&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;rolesQuery&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;select role from user_roles where user_id = ?&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;/mapping-module&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;/mapping&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;/security-domain&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;authentication&lt;/code&gt; portion of the security domain refers to a JAAS LoginModule shipped with the CAS extension, which simply verifies that the identity
assertion comes from the CAS extension and not somewhere else. Then the &lt;code&gt;mapping&lt;/code&gt; portion (&lt;a href=&#34;https://docs.wildfly.org/14/Admin_Guide.html#mapping&#34;&gt;documented here&lt;/a&gt;)
looks up the given user in a database to find what roles it should be assigned.&lt;/p&gt;
&lt;p&gt;The last piece of the puzzle is a CAS deployment descriptor for our application, which activates cas-extension for that application. In its simplest form, this
is an empty file in the right place, but ours ended up a little more complex. It identifies both the CAS profile we want to use (unnecessary in this case, as
there’s only one CAS profile on the system, but it helped keep things more clear in our minds), and instructs the extension to load some other libraries into
our 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-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:#b06;font-weight:bold&#34;&gt;&amp;lt;cas&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;xmlns=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;urn:soulwing.org:cas:1.0&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;profile&amp;gt;&lt;/span&gt;default&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/profile&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;add-api-dependencies/&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;/cas&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This configuration proved sufficient to let users log in and use the application, but as is sometimes the case with single sign-on, we needed a little more work
to let them log out properly. Each application in the suite sets a cookie in the user’s browser to identify its session. The CAS server likewise sets a cookie.
When a user logs out of the application, that application’s session cookie is destroyed, but we also need to destroy the CAS server’s session cookie as well as
the other applications’ cookies. Single log-out can be complicated, and I won’t go into the full setup here. One reason the CAS deployment descriptor loads
cas-extension libraries was so we could use cas-extension to generate the proper logout URL, and redirect our users to that URL once the application has
destroyed its own session.&lt;/p&gt;
&lt;h3 id=&#34;configuring-spring-authentication&#34;&gt;Configuring Spring Authentication&lt;/h3&gt;
&lt;p&gt;Another Java-based application in our suite uses Spring Security. &lt;a href=&#34;https://docs.spring.io/spring-security/site/docs/3.0.x/reference/cas.html&#34;&gt;This document&lt;/a&gt;
describes the bulk of the configuration, which seemed less straightforward than for cas-extension, but follows essentially the same mechanism. Here we
configured a Spring
&lt;a href=&#34;https://docs.spring.io/spring-security/site/docs/3.2.3.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetailsService.html&#34;&gt;UserDetailsService&lt;/a&gt;
to execute the same database query we used above to find the user’s roles. I’m not fully conversant in the large stack of beans Spring uses to manage the
process, and it took some time to get this configuration sorted out.&lt;/p&gt;
&lt;h3 id=&#34;enter-php&#34;&gt;Enter PHP&lt;/h3&gt;
&lt;p&gt;Two of these applications use PHP, which meant yet another configuration. Apereo maintains a &lt;a href=&#34;https://github.com/apereo/phpCAS&#34;&gt;PHP client&lt;/a&gt;, which includes
several helpful examples. I tracked down the part of the application that authenticates users, and replaced the existing code with calls to phpCAS:&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;phpCAS::&lt;span style=&#34;color:#369&#34;&gt;client&lt;/span&gt;(CAS_VERSION_2_0, &lt;span style=&#34;color:#369&#34;&gt;$phpCASHost&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$phpCASPort&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$phpCASContext&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;phpCAS::&lt;span style=&#34;color:#369&#34;&gt;forceAuthentication&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$_SESSION&lt;/span&gt;[EXPORT_SERVERNAME][&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;umdid&amp;#39;&lt;/span&gt;] = phpCAS::&lt;span style=&#34;color:#369&#34;&gt;getUser&lt;/span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;forceAuthentication&lt;/code&gt; call determines the current phase of the authentication process this request is in, whether it’s unauthenticated, fully authenticated, or
requires service ticket validation, and responds appropriately. We then set a session variable to the ID of the authenticated user, which replicates what
the original authentication code would have done.&lt;/p&gt;
&lt;p&gt;One of these two applications requires authenticated access to a REST API exposed by the Wildfly application. CAS calls this “proxy” authentication, when one
application requests access to another. Here, CAS issues not only its usual service ticket, but also a “proxy granting ticket”. When the application wants to
use the API, it asks the CAS server for a service ticket, using the proxy granting ticket. The CAS server itself requires some new configuration in this case,
but for the PHP code, the only difference in the login phase from the simpler, non-proxy case is that we call &lt;code&gt;phpCAS::proxy&lt;/code&gt; instead of &lt;code&gt;phpCAS::client&lt;/code&gt; to
configure CAS. Later, when calling the service itself, we used more phpCAS services in place of the cURL library the original used.&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:#369&#34;&gt;$service&lt;/span&gt; = \phpCAS::&lt;span style=&#34;color:#369&#34;&gt;getProxiedService&lt;/span&gt;(PHPCAS_PROXIED_SERVICE_HTTP_GET);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$service&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;setUrl&lt;/span&gt;(&lt;span style=&#34;color:#369&#34;&gt;$serviceURL&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$service&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;send&lt;/span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;the-return-of-header-authentication&#34;&gt;The return of header authentication&lt;/h3&gt;
&lt;p&gt;Finally, we have a few automated tasks which use various APIs, and need to authenticate. We can’t redirect requests to a CAS server and expect a user to provide
credentials, so we’ve taken our cue from the applications’ original form, and configured CAS to recognize a “trusted header”. We add this header to any requests
issued by these automated jobs. Of course, we’ve also configured the proxy to disallow this header from any systems outside our internal network.&lt;/p&gt;
&lt;h3 id=&#34;a-few-loose-ends&#34;&gt;A few loose ends&lt;/h3&gt;
&lt;p&gt;Of course, there were other considerations in this project that I’ve not covered here. Configuring CAS itself wasn’t necessarily straightforward, and included a
custom authentication module I hope to describe in a later article. Selecting among CAS server’s available
&lt;a href=&#34;https://apereo.github.io/cas/6.1.x/installation/Configuring-Servlet-Container.html&#34;&gt;deployment&lt;/a&gt;
&lt;a href=&#34;https://apereo.github.io/cas/6.1.x/installation/Docker-Installation.html&#34;&gt;options&lt;/a&gt; and fitting the winner into our existing infrastructure in a way that makes
it easy to manage and monitor was another task entirely. We needed to customize the server’s default user interface to prevent it from offering users an
imaginary method to recover forgotten passwords. The series of redirected browser requests involved in the CAS protocol presents a notable performance impact
under some circumstances. And it has taken me no small effort to learn to appreciate the CAS server’s sometimes distressingly circular
&lt;a href=&#34;https://apereo.github.io/cas/6.1.x/index.html&#34;&gt;documentation&lt;/a&gt;. But several months into the project, CAS seems to be working well enough for our purposes that
other users of the same application suite have begun to express interest.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>How to Migrate from Microsoft SQL Server to PostgreSQL</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2019/01/migrate-from-sql-server-to-postgresql/"/>
      <id>https://www.endpointdev.com/blog/2019/01/migrate-from-sql-server-to-postgresql/</id>
      <published>2019-01-23T00:00:00+00:00</published>
      <author>
        <name>Selvakumar Arumugam</name>
      </author>
      <content type="html">
        &lt;img src=&#34;/blog/2019/01/migrate-from-sql-server-to-postgresql/sql-server-to-postgres.jpg&#34; alt=&#39;SQL server to Postgres&#39; /&gt;
&lt;p&gt;One of our clients had a Java-​based application stack on Linux that connected to a pretty old version of SQL Server on Windows. We wanted to migrate the entire system to a more consistent unified stack that developers are efficient with, and that is current so it receives regular updates.&lt;/p&gt;
&lt;p&gt;We decided to migrate the database from SQL Server to PostgreSQL on Linux because porting the database, while not entirely quick or simple, was still much simpler than porting the app to .NET/C# would have been. Rewriting the application would have taken far longer, been much riskier to the business, and cost a lot more.&lt;/p&gt;
&lt;p&gt;I experimented with a few approaches to the migration and decided to go with the process of schema migration and then the data migration approach which is referred to on the Postgres wiki. Let’s walk through the process of migration step by step.&lt;/p&gt;
&lt;h3 id=&#34;schema-migration&#34;&gt;Schema Migration&lt;/h3&gt;
&lt;p&gt;A schema of the SQL Server database tables and views needs to be exported to perform schema conversion. The following steps will show you how to export the schema.&lt;/p&gt;
&lt;h4 id=&#34;export-sql-server-database-schema&#34;&gt;Export SQL Server Database Schema&lt;/h4&gt;
&lt;p&gt;In SQL Management Studio, right click on the database and select Tasks → Generate Scripts.&lt;/p&gt;
&lt;img src=&#34;/blog/2019/01/migrate-from-sql-server-to-postgresql/generate-scripts.png&#34; alt=&#39;Generate Scripts&#39; /&gt;
&lt;p&gt;Choose “Select specific database objects” and check only your application schema Tables (untick dbo schema objects and others if any).&lt;/p&gt;
&lt;img src=&#34;/blog/2019/01/migrate-from-sql-server-to-postgresql/choose-tables.png&#34; alt=&#34;Choose tables&#34; /&gt;
&lt;p&gt;Ensure that “Types of data to script” in advanced options is set to “Schema only”.&lt;/p&gt;
&lt;img src=&#34;/blog/2019/01/migrate-from-sql-server-to-postgresql/schema-only.png&#34; alt=&#34;Schema Only&#34; /&gt;
&lt;p&gt;Review and save the database tables schema file &lt;code&gt;tables.sql&lt;/code&gt;. Use WinSCP and public key auth to transfer &lt;code&gt;tables.sql&lt;/code&gt; to the Linux server.&lt;/p&gt;
&lt;h4 id=&#34;convert-schema-from-sql-server-to-postgres&#34;&gt;Convert Schema from SQL Server to Postgres&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/dalibo/sqlserver2pgsql&#34;&gt;sqlserver2pgsql&lt;/a&gt; is a good migration tool written in Perl to convert SQL Server schemas to Postgres schemas. Clone it from GitHub to your database server and execute the following commands to convert the tables schema:&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/dalibo/sqlserver2pgsql.git
&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; sqlserver2pgsql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ perl sqlserver2pgsql.pl -f tables.sql -b tables-before.sql -a tables-after.sql -u tables-unsure.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The converted schema will be available in &lt;code&gt;tables-before.sql&lt;/code&gt; and statements to create constraints will be in &lt;code&gt;tables-after.sql&lt;/code&gt; to execute after data migration. Just review &lt;code&gt;tables-unsure.sql&lt;/code&gt; and do what’s needed if there are any tables not converted by the tool. If you want to change any schema names in Postgres, you can rename them now in the SQL file, e.g.:&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;$ sed -i ‘s/sql_server_schema/public/g’ *.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;setup-postgres-database&#34;&gt;Setup Postgres Database:&lt;/h4&gt;
&lt;p&gt;Hopefully, you have your Postgres database ready in your server. If not, install the latest version of Postgres on your server. Then create a Postgres user and database with permissions granted to the user.&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&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;USER&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&amp;lt;user_name&amp;gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;WITH&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;LOGIN&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;NOSUPERUSER&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;INHERIT&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 style=&#34;color:#080;font-weight:bold&#34;&gt;NOCREATEDB&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;NOCREATEROLE&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;NOREPLICATION;&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;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&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;DATABASE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&amp;lt;database_name&amp;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 style=&#34;color:#080;font-weight:bold&#34;&gt;WITH&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 style=&#34;color:#080;font-weight:bold&#34;&gt;OWNER&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&amp;lt;user_name&amp;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 style=&#34;color:#080;font-weight:bold&#34;&gt;ENCODING&lt;/span&gt;&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:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;UTF8&amp;#39;&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;LC_COLLATE&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:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;en_US.UTF-8&amp;#39;&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;LC_CTYPE&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:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;en_US.UTF-8&amp;#39;&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;TABLESPACE&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;pg_default&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 style=&#34;color:#080;font-weight:bold&#34;&gt;CONNECTION&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;LIMIT&lt;/span&gt;&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:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once the database and user account are ready, load the converted &lt;code&gt;tables-before.sql&lt;/code&gt; script into your database to create tables. Then we can move forward with data migration.&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;psql -U user_name -p &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5432&lt;/span&gt; -h localhost -d database_name -f tables-before.sql
&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&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;database_name&lt;/span&gt;=&lt;span style=&#34;color:#888&#34;&gt;# \i /path/to/tables-before.sql&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;data-migration&#34;&gt;Data Migration&lt;/h3&gt;
&lt;p&gt;Data migration through data dump and restore makes the process cumbersome, with a huge manual process, data type mismatches, date formats, etc. It is wise to use existing stable systems instead of investing more time into it.&lt;/p&gt;
&lt;h4 id=&#34;pentaho-data-integration&#34;&gt;Pentaho Data Integration&lt;/h4&gt;
&lt;p&gt;Pentaho offers various stable data-​centric products. Pentaho Data Integration (PDI) is an ETL tool which provides great support for migrating data between different databases without manual intervention. The community edition of PDI is good enough to perform our task here. It needs to establish a connection to both the source and destination databases. Then it will do the rest of work on migrating data from SQL server to Postgres database by executing a PDI job.&lt;/p&gt;
&lt;p&gt;Download Pentaho Data Integration Community Edition and extract the tarball in your local environment. See:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://community.hitachivantara.com/community/products-and-solutions/pentaho/&#34;&gt;https://community.hitachivantara.com/community/products-and-solutions/pentaho/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://community.hitachivantara.com/docs/DOC-1009931-downloads&#34;&gt;https://community.hitachivantara.com/docs/DOC-1009931-downloads&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Run &lt;code&gt;spoon.sh&lt;/code&gt; to open the GUI application in your local environment.&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;$ &lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; pentaho/data-integration
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ./spoon.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create connections to both SQL Server and Postgres databases in PDI.&lt;/p&gt;
&lt;p&gt;1. Create a New Job.&lt;/p&gt;
&lt;p&gt;File → New → Job&lt;/p&gt;
&lt;p&gt;2. Create Source Database Connection.&lt;/p&gt;
&lt;p&gt;Click View in left sidebar → Right Click ‘Database Connections’ → Choose New → Provide SQL Server connection details&lt;/p&gt;
&lt;img src=&#34;/blog/2019/01/migrate-from-sql-server-to-postgresql/sqlserver-database-connection.png&#34; alt=&#34;SQL Server Database&#34; /&gt;
&lt;p&gt;3. Create Destination Database Connection.&lt;/p&gt;
&lt;p&gt;Click View in left sidebar → Right Click ‘Database Connections’ → Choose New → Provide Postgres connection details&lt;/p&gt;
&lt;img src=&#34;/blog/2019/01/migrate-from-sql-server-to-postgresql/postgres-database-connection.png&#34; alt=&#34;PostgreSQL Database&#34; /&gt;
&lt;p&gt;4. From Wizard menu, choose Copy Tables Wizard.&lt;/p&gt;
&lt;p&gt;Tools → Wizard → Copy Tables&lt;/p&gt;
&lt;p&gt;5. Choose Source and Destination databases.&lt;/p&gt;
&lt;img src=&#34;/blog/2019/01/migrate-from-sql-server-to-postgresql/source-destination.png&#34; alt=&#34;Source and Destination&#34; /&gt;
&lt;p&gt;6. Select the list of tables to migrate.&lt;/p&gt;
&lt;img src=&#34;/blog/2019/01/migrate-from-sql-server-to-postgresql/source-destination.png&#34; alt=&#34;Source and Destination&#34; /&gt;
&lt;p&gt;7. Move forward to choose the path for job and transformation files.&lt;/p&gt;
&lt;img src=&#34;/blog/2019/01/migrate-from-sql-server-to-postgresql/create-job.png&#34; alt=&#34;Create Job&#34; /&gt;
&lt;p&gt;8. The transformations were created to copy data from source to destination database.&lt;/p&gt;
&lt;img src=&#34;/blog/2019/01/migrate-from-sql-server-to-postgresql/job-view.png&#34; alt=&#34;Job Steps&#34; /&gt;
&lt;p&gt;9. Copy the Pentaho Data Integration tarball and job with transformations to the Postgres server to avoid network latency on data migration.&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;$ tar -cvzf pdi-migration-job.tar.gz pdi-migration-job/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rsync -azP data-integration.zip pdi-migration-job.tar.gz user@server:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;10. Check Postgres server to SQL Server database access (based on architecture design at your end).&lt;/p&gt;
&lt;p&gt;Establish SSH tunneling to connect to SQL Server through the application server.&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;$ cat config
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;host tunnel-server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Hostname &amp;lt;application_server&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Port &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;    User root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    LocalForward &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1433&lt;/span&gt; &amp;lt;ipaddress&amp;gt;:1433
&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;$ ssh tunnel-server
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ telnet localhost &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1433&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;pdi-job-execution&#34;&gt;PDI Job Execution&lt;/h4&gt;
&lt;p&gt;Execute PDI job using Pentaho kitchen utility on the database server. Add a kettle configuration to avoid Pentaho considering empty values as NULL values which affects NOT NULL constraints.&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;$ cat .kettle/kettle.properties
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;KETTLE_EMPTY_STRING_DIFFERS_FROM_NULL&lt;/span&gt;=Y&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Confirm IP address for database servers’ connections and execute the job using &lt;code&gt;kitchen.sh&lt;/code&gt;, a command-​line utility to execute PDI jobs.&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;$ ./kitchen.sh -file=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/path/to/pdi-migration-job.kjb&amp;#34;&lt;/span&gt; -level=Basic | tee pdi-migration-job.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The data migration process took around 30 minutes to copy 10GB of data from SQL Server to Postgres database over network.&lt;/p&gt;
&lt;p&gt;Output:&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-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2018/08/23 11:16:52 - SQLServerToPostgres20180823 - Job execution finished
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2018/08/23 11:16:52 - Kitchen - Finished!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2018/08/23 11:16:52 - Kitchen - Start=2018/08/23 10:51:00.701, Stop=2018/08/23 11:16:52.951
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2018/08/23 11:16:52 - Kitchen - Processing ended after 25 minutes and 52 seconds (1552 seconds total).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We ran into a space problem while copying a large table and handled it by reducing the number of rows size in the corresponding table transformation file. Here’s a &lt;a href=&#34;https://forums.pentaho.com/threads/72409-Kettle-out-of-memory-error-loading-a-large-fact-table/&#34;&gt;discussion of the problem&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Fix:&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;vi **table_name**.ktr
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;size_rowset&amp;gt;100&amp;lt;/size_rowset&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;sed &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;s/&amp;lt;size_rowset&amp;gt;10000&amp;lt;\/size_rowset&amp;gt;/&amp;lt;size_rowset&amp;gt;100&amp;lt;\/size_rowset&amp;gt;/&amp;#39;&lt;/span&gt; *table_name*&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once the data migration is completed, execute the &lt;code&gt;tables-after.sql&lt;/code&gt; schema-​migration script to apply constraints.&lt;/p&gt;
&lt;h4 id=&#34;migrate-views&#34;&gt;Migrate Views&lt;/h4&gt;
&lt;p&gt;Follow the same steps to convert the &lt;code&gt;views.sql&lt;/code&gt; schema. Right click on the database and click on Tasks → Generate Script → Export only views.&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;$ perl sqlserver2pgsql.pl -f views.sql -b views-before.sql -a views-after.sql -u views-unsure.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;migrate-functions&#34;&gt;Migrate Functions&lt;/h4&gt;
&lt;p&gt;The functions migration requires skill and syntax awareness of both SQL Server and Postgres. The functions need to validated and tested properly after rewriting for Postgres. Place all rewritten functions into &lt;code&gt;postgres-function.sql&lt;/code&gt; and load into the database as part of the migration process.&lt;/p&gt;
&lt;h3 id=&#34;most-common-errors&#34;&gt;Most Common Errors&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ERROR:  syntax error at or near &amp;quot;[&amp;quot;&lt;/code&gt;&lt;br&gt;
Remove SQL Server square brackets quoting around column and table names.&lt;br&gt;
SELECT [user_id] → SELECT user_id&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ERROR:  operator does not exist: character varying = integer&lt;/code&gt;&lt;br&gt;
Type casting on comparison&lt;br&gt;
AND column_name in (1, -1) → AND column_name in (&amp;lsquo;1&amp;rsquo;, &amp;lsquo;-1&amp;rsquo;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ERROR:  syntax error at or near &amp;quot;,&amp;quot;&lt;/code&gt;&lt;br&gt;
Datatype conversion&lt;br&gt;
convert(varchar(10),column_name) → column_name::text&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ERROR: column &amp;quot;user_id&amp;quot; of relation &amp;quot;user&amp;quot; does not exist&lt;/code&gt;&lt;br&gt;
No double quotes on mixed-​case column names (unless used everywhere)&lt;br&gt;
INSERT INTO user (&amp;ldquo;user_id&amp;rdquo;) VALUES (1) → INSERT INTO user (user_id) VALUES (1)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ERROR: column &amp;quot;mm&amp;quot; does not exist&lt;/code&gt;&lt;br&gt;
DATEADD → INTERVAL&lt;br&gt;
DATEADD(mm,-6,GETDATE()) → CURRENT_DATE - INTERVAL &amp;lsquo;6 months&amp;rsquo;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ERROR: column &amp;quot;varchar&amp;quot; does not exist&lt;/code&gt;&lt;br&gt;
Convert date to USA format&lt;br&gt;
convert(varchar, tc_agreed_dt, 101) → to_char(CURRENT_TIMESTAMP, &amp;lsquo;MM/DD/YYYY&amp;rsquo;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;result&#34;&gt;Result&lt;/h3&gt;
&lt;p&gt;After migration, we performed extensive testing on the application and optimized the queries in various modules. We also performed a benchmark test on speed and performance between the new and old systems. The migration paid off with a promising result of 40% average gain on overall performance of the application. That reflects the newer server hardware as well as the query optimization work, not solely the move to Postgres.&lt;/p&gt;
&lt;p&gt;The entire migration was automated with a script to test multiple times and reduce manual intervention to perform error-​free process. The automated script is available to customize based on your scenario: &lt;a href=&#34;/blog/2019/01/migrate-from-sql-server-to-postgresql/sqlserver-postgres-migration-automation.sh&#34;&gt;sqlserver-postgres-migration-automation.sh&lt;/a&gt;&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>TriSano Case Study</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2017/01/trisano-case-study/"/>
      <id>https://www.endpointdev.com/blog/2017/01/trisano-case-study/</id>
      <published>2017-01-24T00:00:00+00:00</published>
      <author>
        <name>Elizabeth Garrett Christensen</name>
      </author>
      <content type="html">
        &lt;h3 id=&#34;overview&#34;&gt;Overview&lt;/h3&gt;
&lt;p&gt;End Point has been working with state and local health agencies since 2008. We host disease outbreak surveillance and management systems and have expertise providing clients with the sophisticated case management tools they need to deliver in-house analysis, visualization, and reporting—​combined with the flexibility to comply with changing state and federal requirements. End Point provides the hosting infrastructure, database, reporting systems, and customizations that agencies need in order to service to their populations.&lt;/p&gt;
&lt;p&gt;Our work with health agencies is a great example of End Point’s ability to use our experience in open source technology, Ruby on Rails, manage and back up large secure datasets, and integrate reporting systems to build and support a full-stack application. We will discuss one such client in this case study.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; float: right; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2017/01/trisano-case-study/image-0.jpeg&#34; imageanchor=&#34;1&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;376&#34; src=&#34;/blog/2017/01/trisano-case-study/image-0.jpeg&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 id=&#34;why-end-point&#34;&gt;Why End Point?&lt;/h3&gt;
&lt;p&gt;End Point is a good fit for this project because of our expertise in several areas including reporting and our hosting capabilities. End Point has had a long history of consultant experts in PostgreSQL and Ruby on Rails, which are the core software behind this application.&lt;/p&gt;
&lt;p&gt;Also, End Point specializes in customizing open-source software, which can save not-for-profit and state agencies valuable budget dollars they can invest in other social programs.&lt;/p&gt;
&lt;p&gt;Due to the secure nature of the medical data in these database, we and our clients must adhere to all HIPAA and CDC policies regarding hosting of data handling, server hosting, and staff authorization and access auditing.&lt;/p&gt;
&lt;h3 id=&#34;team&#34;&gt;Team&lt;/h3&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; float: left; text-align: center; padding:10px;&#34;&gt;&lt;a href=&#34;/blog/2017/01/trisano-case-study/image-1-big.jpeg&#34; imageanchor=&#34;1&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;100&#34; src=&#34;/blog/2017/01/trisano-case-study/image-1.jpeg&#34; width=&#34;100&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h4 id=&#34;steve-yoman&#34;&gt;Steve Yoman&lt;/h4&gt;
&lt;p&gt;Steve serves as the project manager for both communication and internal development for End Point’s relationship with the client. Steve brings many years in project management to the table for this job and does a great job keeping track of every last detail, quote, and contract item.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; float: left; text-align: center; padding:10px;&#34;&gt;&lt;a href=&#34;/blog/2017/01/trisano-case-study/image-2-big.jpeg&#34; imageanchor=&#34;1&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;100&#34; src=&#34;/blog/2017/01/trisano-case-study/image-2.jpeg&#34; width=&#34;100&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h4 id=&#34;selvakumar-arumugam&#34;&gt;Selvakumar Arumugam&lt;/h4&gt;
&lt;p&gt;Selva is one of those rare engineers who is gifted with both development and DevOps expertise. He is the main developer on daily tasks related to the disease tracking system. He also does a great job navigating a complex hosting environment and has helped the client make strides towards their future goals.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; float: left; text-align: center; padding:10px;&#34;&gt;&lt;a href=&#34;/blog/2017/01/trisano-case-study/image-3-big.jpeg&#34; imageanchor=&#34;1&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;100&#34; src=&#34;/blog/2017/01/trisano-case-study/image-3.jpeg&#34; width=&#34;100&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h4 id=&#34;josh-tolley&#34;&gt;Josh Tolley&lt;/h4&gt;
&lt;p&gt;Josh is one of End Point’s most knowledgeable database and reporting experts. Josh’s knowledge of PostgreSQL is extremely helpful to make sure that the data is secure and stable. He built and maintains a standalone reporting application based on Pentaho.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; float: right; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2017/01/trisano-case-study/image-4-big.jpeg&#34; imageanchor=&#34;1&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2017/01/trisano-case-study/image-4.jpeg&#34; width=&#34;500&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 id=&#34;application&#34;&gt;Application&lt;/h3&gt;
&lt;p&gt;The disease tracking system consists of several applications including a web application, reporting application, two messaging areas, and SOAP services that relay data between internal and external systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TriSano&lt;/strong&gt;: The disease tracking web app is an open source Ruby on Rails application based on the TriSano product, originally built at the Collaborative Software Initiative. This is a role-based web application where large amounts of epidemiological data can be entered manually or by data transfer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pentaho&lt;/strong&gt;: Pentaho is a PostgreSQL reporting application that allows you to run a separate reporting service or embed reports into your website. Pentaho has a community version and an enterprise version, which is what is used on this particular project. This reporting application provides OLAP services, dashboarding, and generates ad hoc and static reports. Josh Tolley customized Pentaho so that the client can download or create custom reports depending on their needs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Two Messaging Area applications&lt;/strong&gt;: The TriSano system also serves as the central repository for messaging feeds used to collect data from local health care providers, laboratories throughout the state, and the CDC.&lt;/p&gt;
&lt;p&gt;SOAP services run between the TriSano web app, the Pentaho reporting application, and the client’s data systems translate messages into the correct formats and relay the information to each application.&lt;/p&gt;
&lt;h3 id=&#34;into-the-future&#34;&gt;Into the Future&lt;/h3&gt;
&lt;p&gt;Based on the success over 9+ years working on this project, the client continues to work with their End Point team to manage their few non open-source software licenses, create long term security strategies, and plan and implement all of their needs related to the continuous improvement and changes in epidemiology tracking. We partner with the client so they can focus their efforts on reading results and planning for the future health of their citizens. This ongoing partnership is something End Point is very proud to be a part of and we hope to continue our work in this field well into the future.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Analyzer Reports with Geo Map Option in Pentaho 5 BI Server</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/09/analyzer-reports-with-geo-map-option-in/"/>
      <id>https://www.endpointdev.com/blog/2014/09/analyzer-reports-with-geo-map-option-in/</id>
      <published>2014-09-12T00:00:00+00:00</published>
      <author>
        <name>Selvakumar Arumugam</name>
      </author>
      <content type="html">
        &lt;p&gt;The “Geo Map” option in Analyzer Reports provides a feature to visualize data with geographic locations. We will learn how to design a Mondrian schema and configure Pentaho to make use of the “Geo Map” feature in the Analyzer Reports. This article will show us how to set this feature up step by step.&lt;/p&gt;
&lt;h3 id=&#34;enable-geo-map-feature-on-geographic-fields-in-mondrian-schema&#34;&gt;Enable Geo Map feature on Geographic fields in Mondrian Schema&lt;/h3&gt;
&lt;p&gt;The Mondrian schema has two main categories called Dimensions and Measures. The Dimensions are defined as levels in the Mondrian schema. The Geographic fields should have two additional annotations to use Geo Map. The two annotations are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Data.Role — defines the type of level generally; for this type of node, this must be set to ‘Geography’.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Geo.Role — defines the geographical classification in a hierarchy. These can be either predefined roles (‘country’, ‘state’, ‘city’, ‘postalcode’) or custom roles.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;sample-level-with-annotation&#34;&gt;Sample Level with Annotation:&lt;/h4&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:#b06;font-weight:bold&#34;&gt;&amp;lt;Level&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;Country Name&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;visible=&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;column=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;country&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;String&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;uniqueMembers=&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;levelType=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Regular&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;hideMemberIf=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Never&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;Annotations&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;Annotation&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;Data.Role&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[Geography]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/Annotation&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;Annotation&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;Geo.Role&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[country]]&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/Annotation&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;/Annotations&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;/Level&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;geographic-fields-and-datasets-in-database&#34;&gt;Geographic fields and datasets in database&lt;/h3&gt;
&lt;p&gt;I have created a sample table with the fields containing geographic locations for dimensions and aggregated value for measures. The sample population table contains Pentaho-defined geographic locations ‘country’, ‘state’, ‘city’ and aggregated population count for those geographic fields.&lt;/p&gt;
&lt;h4 id=&#34;population-table-design-and-datasets&#34;&gt;‘Population’ table design and datasets:&lt;/h4&gt;
&lt;p&gt;Here we create a sample population table with geographic fields and the population count in a PostgreSQL database.&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;CREATE&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;TABLE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;population&lt;span style=&#34;color:#bbb&#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;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;INT&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;PRIMARY&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;KEY&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;NOT&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;NULL&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;country&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;TEXT&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;NOT&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;NULL&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 style=&#34;color:#080;font-weight:bold&#34;&gt;state&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;TEXT&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;NOT&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;NULL&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;city&lt;span style=&#34;color:#bbb&#34;&gt;         &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;TEXT&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;NOT&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;NULL&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 style=&#34;color:#080;font-weight:bold&#34;&gt;count&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;        &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;INT&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;NOT&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;NULL&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next we load population data into the table for 4 cities of 2 states in USA. (Population data for more geographic locations in USA are available at &lt;a href=&#34;https://www.google.com/publicdata/explore?ds=kf7tgg1uo9ude_&#34;&gt;USA Population&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-sql&#34; data-lang=&#34;sql&#34;&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 style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&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;FROM&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;population;&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;id&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;|&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;country&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;state&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;    &lt;/span&gt;|&lt;span style=&#34;color:#bbb&#34;&gt;     &lt;/span&gt;city&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;count&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 style=&#34;color:#888&#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;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;|&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;USA&lt;span style=&#34;color:#bbb&#34;&gt;     &lt;/span&gt;|&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;California&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;|&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;Los&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;Angeles&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:#00d;font-weight:bold&#34;&gt;3857800&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 style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;|&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;USA&lt;span style=&#34;color:#bbb&#34;&gt;     &lt;/span&gt;|&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;California&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;|&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;San&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;Francisco&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:#00d;font-weight:bold&#34;&gt;825863&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 style=&#34;color:#00d;font-weight:bold&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;|&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;USA&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;York&lt;span style=&#34;color:#bbb&#34;&gt;   &lt;/span&gt;|&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;Hilton&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:#00d;font-weight:bold&#34;&gt;5974&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 style=&#34;color:#00d;font-weight:bold&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;|&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;USA&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;York&lt;span style=&#34;color:#bbb&#34;&gt;   &lt;/span&gt;|&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;Johnsburg&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:#00d;font-weight:bold&#34;&gt;2390&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&#34;https://docs.google.com/uc?export=download&amp;amp;id=0Bxu-zrDMylMqUVpjZFh1LXN1STA&#34;&gt;Download&lt;/a&gt; the sql dump file with table schema and datasets.&lt;/p&gt;
&lt;h3 id=&#34;design-a-mondrian-schema-with-geographic-support&#34;&gt;Design a Mondrian Schema with Geographic Support&lt;/h3&gt;
&lt;p&gt;Pentaho provides a tool called “Schema Work Bench” to design a Mondrian schema for a specific table’s data. We can create a new Mondrian schema for the table by selecting File -&amp;gt; New -&amp;gt; Schema. The picture below depicts the hierarchy level of the Mondrian schema elements.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2014/09/analyzer-reports-with-geo-map-option-in/image-0.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;536&#34; src=&#34;/blog/2014/09/analyzer-reports-with-geo-map-option-in/image-0.png&#34; width=&#34;640&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 id=&#34;publish-the-mondrian-schema-to-pentaho&#34;&gt;Publish the Mondrian schema to Pentaho&lt;/h3&gt;
&lt;p&gt;The publish process requires the JDBC datasource to have access to database. Create a JDBC datasource in the manage datasources wizard with necessary input values.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2014/09/analyzer-reports-with-geo-map-option-in/image-1.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;484&#34; src=&#34;/blog/2014/09/analyzer-reports-with-geo-map-option-in/image-1.png&#34; width=&#34;640&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Once the JDBC datasource has been created in Pentaho server, the Mondrian schema can be published from the Schema Work Bench.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2014/09/analyzer-reports-with-geo-map-option-in/image-2.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2014/09/analyzer-reports-with-geo-map-option-in/image-2.png&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.google.com/uc?export=download&amp;amp;id=0Bxu-zrDMylMqaE5idUJwVW9LWnc&#34;&gt;Download&lt;/a&gt; the Mondrian schema xml to view the schema, cube, table, dimension, hierarchy, level, annotations, measures elements and corresponding attribute values.&lt;/p&gt;
&lt;p&gt;The Mondrian schema xml can be imported directly into Pentaho server to create an analysis datasource.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2014/09/analyzer-reports-with-geo-map-option-in/image-3.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2014/09/analyzer-reports-with-geo-map-option-in/image-3.png&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 id=&#34;create-a-analyzer-report-with-geo-map&#34;&gt;Create a Analyzer Report with Geo Map&lt;/h3&gt;
&lt;p&gt;Add the necessary geographic fields under “Rows” and population count under “Measure” to create a basic analyzer report.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2014/09/analyzer-reports-with-geo-map-option-in/image-4.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;278&#34; src=&#34;/blog/2014/09/analyzer-reports-with-geo-map-option-in/image-4.png&#34; width=&#34;640&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Change the report type to “Geo Map” through the right top corner options to view the visualized data. Congratulations, you’re done!&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;
&lt;a href=&#34;/blog/2014/09/analyzer-reports-with-geo-map-option-in/image-5.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;&lt;img border=&#34;0&#34; height=&#34;220&#34; src=&#34;/blog/2014/09/analyzer-reports-with-geo-map-option-in/image-5.png&#34; width=&#34;640&#34;/&gt;&lt;/a&gt;&lt;/div&gt;

      </content>
    </entry>
  
    <entry>
      <title>Install Pentaho BI Server 4.8 Community Edition with PostgreSQL Repository</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/11/install-pentaho-bi-server-48-community/"/>
      <id>https://www.endpointdev.com/blog/2013/11/install-pentaho-bi-server-48-community/</id>
      <published>2013-11-07T00:00:00+00:00</published>
      <author>
        <name>Selvakumar Arumugam</name>
      </author>
      <content type="html">
        &lt;p&gt;Pentaho BI server community edition can be installed through an archive file available from SourceForge.&lt;/p&gt;
&lt;p&gt;Prerequisites&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java 6&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Download Pentaho BI Server installation file (biserver-ce-4.8.0-stable.zip) from SourceForge: &lt;a href=&#34;http://sourceforge.net/projects/pentaho/files/Business%20Intelligence%20Server/4.8.0-stable&#34;&gt;http://sourceforge.net/projects/pentaho/files/Business%20Intelligence%20Server/4.8.0-stable&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Unzip the archive file and navigate inside biserver-ce to set sh files to executable mode:&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;$ unzip biserver-ce-4.8.0-stable.zip
&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; biserver-ce
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ find . -type f -iname &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;*.sh&amp;#39;&lt;/span&gt; -exec chmod a+x {} &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pentaho community edition uses hsql database as default. Need to create two databases in Postgres for Pentaho. Find the SQL files to create databases under biserver-ce/data/postgresql. database_name, user_name and password are configurable through SQL files. Fix two errors before creating database using SQL files. Comment two lines in below files tables as commented.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;create_quartz_postgresql.sql&lt;/li&gt;
&lt;/ul&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;ALTER&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;TABLE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;qrtz_fired_triggers&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 style=&#34;color:#080;font-weight:bold&#34;&gt;ALTER&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;TRIGGER_NAME&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;TYPE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;VARCHAR&lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&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 style=&#34;color:#080;font-weight:bold&#34;&gt;ALTER&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;TRIGGER_GROUP&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TYPE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;VARCHAR&lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&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 style=&#34;color:#080;font-weight:bold&#34;&gt;ALTER&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;INSTANCE_NAME&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TYPE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;VARCHAR&lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&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 style=&#34;color:#080;font-weight:bold&#34;&gt;ALTER&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;JOB_NAME&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TYPE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;VARCHAR&lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&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 style=&#34;color:#080;font-weight:bold&#34;&gt;ALTER&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;JOB_GROUP&lt;span style=&#34;color:#bbb&#34;&gt;     &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TYPE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;VARCHAR&lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&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 style=&#34;color:#080;font-weight:bold&#34;&gt;ADD&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;COLUMN&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;PRIORITY&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;INTEGER&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;NULL&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 style=&#34;color:#888&#34;&gt;--    ADD COLUMN PRIORITY INTEGER NOT NULL;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;migrate_quartz_postgresql.sql&lt;/li&gt;
&lt;/ul&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-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;ALTER&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;TABLE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;qrtz_fired_triggers&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 style=&#34;color:#080;font-weight:bold&#34;&gt;ALTER&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;TRIGGER_NAME&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;TYPE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;VARCHAR&lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&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 style=&#34;color:#080;font-weight:bold&#34;&gt;ALTER&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;TRIGGER_GROUP&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TYPE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;VARCHAR&lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&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 style=&#34;color:#080;font-weight:bold&#34;&gt;ALTER&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;INSTANCE_NAME&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TYPE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;VARCHAR&lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&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 style=&#34;color:#080;font-weight:bold&#34;&gt;ALTER&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;JOB_NAME&lt;span style=&#34;color:#bbb&#34;&gt;      &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TYPE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;VARCHAR&lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&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 style=&#34;color:#080;font-weight:bold&#34;&gt;ALTER&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;JOB_GROUP&lt;span style=&#34;color:#bbb&#34;&gt;     &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;TYPE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#038&#34;&gt;VARCHAR&lt;/span&gt;(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&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 style=&#34;color:#888&#34;&gt;--    ADD COLUMN PRIORITY INTEGER NOT NULL;
&lt;/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;--    ALTER COLUMN PRIORITY SET NULL;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Modify database name, username &amp;amp; password if necessary and create databases for configuration and scheduling by running below commands.&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;$ psql -U postgres -a -f create_quartz_postgresql.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ psql -U postgres -a -f create_repository_postgresql.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ psql -U postgres -a -f create_sample_datasource_postgresql.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ psql -U postgres -a -f migrate_quartz_postgresql.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ psql -U postgres -a -f migration.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Verify databases quartz (scheduling) and hibernate (configuration) and their tables.&lt;/p&gt;
&lt;p&gt;Now database name, username, password and driver should be configured in following places in files. By default hsql drivers, settings enabled in config files so comment hsql configurations and enable Postgres settings.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;biserver-ce/tomcat/webapps/pentaho/META-INF/context.xml&lt;/li&gt;
&lt;/ul&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:#b06;font-weight:bold&#34;&gt;&amp;lt;Context&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;path=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/pentaho&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;docbase=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;webapps/pentaho/&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;Resource&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;jdbc/Hibernate&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;auth=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Container&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;javax.sql.DataSource&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:#369&#34;&gt;factory=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;org.apache.commons.dbcp.BasicDataSourceFactory&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;maxActive=&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;maxIdle=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;5&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:#369&#34;&gt;maxWait=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10000&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;username=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;hibuser&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;password=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;password&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:#369&#34;&gt;driverClassName=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;org.postgresql.Driver&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;url=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;jdbc:postgresql://localhost:5432/hibernate&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:#369&#34;&gt;validationQuery=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;select 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&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;Resource&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;jdbc/Quartz&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;auth=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Container&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;javax.sql.DataSource&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:#369&#34;&gt;factory=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;org.apache.commons.dbcp.BasicDataSourceFactory&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;maxActive=&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;maxIdle=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;5&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:#369&#34;&gt;maxWait=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10000&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;username=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pentaho_user&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;password=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;password&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:#369&#34;&gt;driverClassName=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;org.postgresql.Driver&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;url=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;jdbc:postgresql://localhost:5432/quartz&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:#369&#34;&gt;validationQuery=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;select 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;/Context&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;biserver-ce/pentaho-solutions/system/applicationContext-spring-security-jdbc.xml&lt;/li&gt;
&lt;/ul&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:#b06;font-weight:bold&#34;&gt;&amp;lt;bean&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;id=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;dataSource&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:#369&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;org.springframework.jdbc.datasource.DriverManagerDataSource&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;property&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;driverClassName&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;org.postgresql.Driver&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;property&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;url&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;jdbc:postgresql://localhost:5432/hibernate&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;property&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;username&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;hibuser&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;property&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;password&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;password&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;/bean&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;biserver-ce/pentaho-solutions/system/applicationContext-spring-security-hibernate.properties&lt;/li&gt;
&lt;/ul&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;jdbc.driver=org.postgresql.Driver
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;jdbc.url=jdbc:postgresql://localhost:5432/hibernate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;jdbc.username=hibuser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;jdbc.password=password
&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;hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;biserver-ce/pentaho-solutions/system/hibernate/hibernate-settings.xml&lt;/li&gt;
&lt;/ul&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:#b06;font-weight:bold&#34;&gt;&amp;lt;config-file&amp;gt;&lt;/span&gt;system/hibernate/postgresql.hibernate.cfg.xml&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/config-file&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;biserver-ce/pentaho-solutions/system/hibernate/postgresql.hibernate.cfg.xml&lt;/li&gt;
&lt;/ul&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:#b06;font-weight:bold&#34;&gt;&amp;lt;property&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;connection.driver_class&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;org.postgresql.Driver&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/property&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;property&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;connection.url&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;jdbc:postgresql://localhost:5432/hibernate&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/property&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;property&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;dialect&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;org.hibernate.dialect.PostgreSQLDialect&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/property&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;property&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;connection.username&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;hibuser&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/property&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;property&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;connection.password&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;password&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/property&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;biserver-ce/pentaho-solutions/system/simple-jndi/jdbc.properties&lt;/li&gt;
&lt;/ul&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;Hibernate/type=javax.sql.DataSource
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hibernate/driver=org.postgresql.Driver
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hibernate/url=jdbc:postgresql://localhost:5432/hibernate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hibernate/user=hibuser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hibernate/password=password
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Quartz/type=javax.sql.DataSource
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Quartz/driver=org.postgresql.Driver
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Quartz/url=jdbc:postgresql://localhost:5432/quartz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Quartz/user=pentaho_user
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Quartz/password=password&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Specify the pentaho solutions path, server url and port in web.xml of tomcat webapp&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;biserver-ce/tomcat/webapps/pentaho/WEB-INF/web.xml&lt;/li&gt;
&lt;/ul&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:#b06;font-weight:bold&#34;&gt;&amp;lt;context-param&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;param-name&amp;gt;&lt;/span&gt;solution-path&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/param-name&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;param-value&amp;gt;&lt;/span&gt;/opt/avr-new/biserver-ce/pentaho-solutions&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/param-value&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;/context-param&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;context-param&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;param-name&amp;gt;&lt;/span&gt;fully-qualified-server-url&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/param-name&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;param-value&amp;gt;&lt;/span&gt;http://localhost:8080/pentaho/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/param-value&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;/context-param&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pentaho can be run tomcat custom ports by modifying the ports in server.xml and web.xml&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;biserver-ce/tomcat/conf/server.xml&lt;/li&gt;
&lt;/ul&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:#b06;font-weight:bold&#34;&gt;&amp;lt;Connector&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;URIEncoding=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;port=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;9090&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;protocol=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;HTTP/1.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:#369&#34;&gt;connectionTimeout=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;20000&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:#369&#34;&gt;redirectPort=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;8443&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;biserver-ce/tomcat/webapps/pentaho/WEB-INF/web.xml &lt;/li&gt;
&lt;/ul&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:#b06;font-weight:bold&#34;&gt;&amp;lt;context-param&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;param-name&amp;gt;&lt;/span&gt;fully-qualified-server-url&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/param-name&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;param-value&amp;gt;&lt;/span&gt;http://localhost:8080/pentaho/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/param-value&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;/context-param&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let’s start the Pentaho BI server and try out its great features. Commands to start and stop the BI server:&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;biserver-ce$ ./start-pentaho.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;biserver-ce$ ./stop-pentaho.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Troubleshooting:&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;biserver-ce$ tail -f tomcat/logs/catalina.out
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;biserver-ce$ tail -f tomcat/logs/pentaho.out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


      </content>
    </entry>
  
    <entry>
      <title>Install Pentaho BI Server 5 Enterprise Edition with PostgreSQL repository</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/11/install-pentaho-bi-server-5-enterprise/"/>
      <id>https://www.endpointdev.com/blog/2013/11/install-pentaho-bi-server-5-enterprise/</id>
      <published>2013-11-07T00:00:00+00:00</published>
      <author>
        <name>Selvakumar Arumugam</name>
      </author>
      <content type="html">
        &lt;p&gt;Pentaho provides different ways to install Pentaho BI server. Each method has its own flexibility in installation.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Installer mode—​Easy to install BA &amp;amp; DI server &amp;amp; tools in one flow with default PostgreSQL repo &amp;amp; default Tomcat server. (New Postgres installed on port 5432.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Archive mode—​BA server installed with own BA repository &amp;amp; default Tomcat server. Necessary tools need to be installed manually.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Manual mode—​BA server installed with own BA repository &amp;amp; own application server (Tomcat or JBoss). Necessary tools need to installed manually.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We have a Postgres instance running on our server and are good with Tomcat as application server so Archive mode of installation is suitable for us. Pentaho installation requires two things be installed before starting with Pentaho installation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java 7&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Archive mode installation files can be accessible only to license purchased users. Download biserver-ee-5.x-dist.zip from Pentaho customer portal with account credentials here: &lt;a href=&#34;https://support.pentaho.com/forums/20413716-Downloads&#34;&gt;https://support.pentaho.com/forums/20413716-Downloads&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Unzip the archive file and you can see the installation files inside extracted directory.&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;$ unzip biserver-ee-5.x-dist.zip
&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; biserver-ee-5.x;ls
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;install.bat  installer.jar  install.sh  license.txt  README.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In remote servers Pentaho can be installed on console mode with -console’. Accept the license and provide the installation path to install Pentaho BI server.&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;$ java -jar installer.jar -console&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Find biserver-ee directory under the installation path and set sh files to executable mode.&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;$ &lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; biserver-ee;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ find . -type f -iname &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;*.sh&amp;#39;&lt;/span&gt; -exec chmod a+x {} &lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let’s create repository databases by running queries in SQL files located at biserver-ee/data/postgresql.&lt;/p&gt;
&lt;p&gt;quartz, hibernate and jackrabbit databases will be created by executing these SQL files. Database names, usernames and password can be changed by modifying in SQL files if required.&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;$ &lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; biserver-ee/data/postgresql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ psql -U postgres -p &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5432&lt;/span&gt; -a -f create_jcr_postgresql.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ psql -U postgres -p &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5432&lt;/span&gt; -a -f create_quartz_postgresql.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ psql -U postgres -p &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5432&lt;/span&gt; -a -f create_repository_postgresql.sql
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ psql -U postgres -p &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5432&lt;/span&gt; -a -f pentaho_mart_postgresql.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pentaho uses postgresql as default database and files are configured to use postgresql. So just verify the database_name, username and password to work with installed postgresql and databases created.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;biserver-ee/pentaho-solutions/system/quartz/quartz.properties&lt;/li&gt;
&lt;/ul&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;org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;biserver-ee/pentaho-solutions/system/hibernate/hibernate-settings.xml&lt;/li&gt;
&lt;/ul&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:#b06;font-weight:bold&#34;&gt;&amp;lt;config-file&amp;gt;&lt;/span&gt;system/hibernate/postgresql.hibernate.cfg.xml&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/config-file&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;biserver-ee/pentaho-solutions/system/hibernate/postgresql.hibernate.cfg.xml&lt;/li&gt;
&lt;/ul&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:#b06;font-weight:bold&#34;&gt;&amp;lt;property&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;connection.driver_class&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;org.postgresql.Driver&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/property&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;property&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;connection.url&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;jdbc:postgresql://localhost:5432/hibernate&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/property&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;property&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;dialect&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;org.hibernate.dialect.PostgreSQLDialect&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/property&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;property&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;connection.username&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;pentaho_user&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/property&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;property&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;connection.password&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;password&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/property&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are more occurrences in this file. Carefully do the necessary changes in all the places.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;biserver-ee/pentaho-solutions/system/jackrabbit/repository.xml&lt;/li&gt;
&lt;li&gt;biserver-ee/pentaho-solutions/system/jackrabbit/repository/workspaces/default/workspace.xml&lt;/li&gt;
&lt;li&gt;biserver-ee/tomcat/webapps/pentaho/META-INF/context.xml&lt;/li&gt;
&lt;/ul&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:#b06;font-weight:bold&#34;&gt;&amp;lt;Resource&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;jdbc/PDI_Operations_Mart&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;auth=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Container&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;javax.sql.DataSource&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:#369&#34;&gt;factory=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;org.apache.commons.dbcp.BasicDataSourceFactory&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;maxActive=&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;maxIdle=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;5&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:#369&#34;&gt;maxWait=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;10000&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;username=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pentaho_user&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;password=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;password&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:#369&#34;&gt;driverClassName=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;org.postgresql.Driver&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;url=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;jdbc:postgresql://localhost:5432/hibernate&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:#369&#34;&gt;validationQuery=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;select 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;/code&gt;&lt;/pre&gt;&lt;/div&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;Download postgresql and h2 drivers then place it under biserver-ee/tomcat/lib&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;postgresql-9.x.jdbc4.jar&lt;/p&gt;
&lt;p&gt;h2-1.2.x.jar&lt;/p&gt;
&lt;p&gt;Change Tomcat port on these two files to run Pentaho on different port.&lt;/p&gt;
&lt;p&gt;Specify the Pentaho solutions path, server URL and port in web.xml of Tomcat webapp.&lt;/p&gt;
&lt;p&gt;biserver-ee/tomcat/webapps/pentaho/WEB-INF/web.xml&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:#b06;font-weight:bold&#34;&gt;&amp;lt;context-param&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;param-name&amp;gt;&lt;/span&gt;solution-path&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/param-name&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;param-value&amp;gt;&lt;/span&gt;$INSTALLATION_PATH/biserver-ee/pentaho-solutions&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/param-value&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;/context-param&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;context-param&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;param-name&amp;gt;&lt;/span&gt;fully-qualified-server-url&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/param-name&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;param-value&amp;gt;&lt;/span&gt;http://localhost:8080/pentaho/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/param-value&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;/context-param&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pentaho can be configured to run on different ports by changing ports on Tomcat server.xml and web.xml&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;biserver-ee/tomcat/biserver-ee/tomcat/server.xml&lt;/li&gt;
&lt;/ul&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:#b06;font-weight:bold&#34;&gt;&amp;lt;Connector&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;URIEncoding&amp;#34;UTF-8&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;port&amp;#34;9090&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;protocol&amp;#34;HTTP/1.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:#a61717;background-color:#e3d2d2&#34;&gt;connectionTimeout&amp;#34;20000&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:#a61717;background-color:#e3d2d2&#34;&gt;redirectPort&amp;#34;8443&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;/code&gt;&lt;/pre&gt;&lt;/div&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;- biserver-ee/tomcat/webapps/pentaho/WEB-INF/web.xml
&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;context-param&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;param-name&amp;gt;&lt;/span&gt;fully-qualified-server-url&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/param-name&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;param-value&amp;gt;&lt;/span&gt;http://localhost:9090/pentaho/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/param-value&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;/context-param&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install license&lt;/p&gt;
&lt;p&gt;A license needs to be installed to use Pentaho. Navigate to the license-installer directory in installation path. Feed license file to install_license.sh, separating more than one license file with spaces.&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;$ ./install_license.sh install ../license/Pentaho&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\ &lt;/span&gt;BI&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\ &lt;/span&gt;Platform&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\ &lt;/span&gt;Enterprise&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\ &lt;/span&gt;Edition.lic&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install plugins&lt;/p&gt;
&lt;p&gt;Archive mode of installation installs only BI Server. Necessary plugins can to be installed manually. Here install the plugins for reporting, analyzer and dashboard. Plugins are available at the same place where download BI server. Download these three files and place at any path on server:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reporting—​pir-plugin-ee-5.x-dist.zip&lt;/li&gt;
&lt;li&gt;Analyzer—​pdd-plugin-ee-5.0.0.1-dist.zip&lt;/li&gt;
&lt;li&gt;Dashboard—​paz-plugin-ee-5.0.0.1-dist.zip&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All the plugins installed through same procedure.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Unzip the plugins and navigate to extracted directory&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;run installer on console, accept the license and provide $INSTALLATION_PATH/biserver-ee/pentaho-solutions/system as location to install plugins&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&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;$ java -jar installer.jar -console&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let’s start the BI server&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;biserver-ee$ ./start-pentaho.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install the licenses for the plugins by login as admin user (default—​Admin:password) or install through the command line:&lt;/p&gt;
&lt;p&gt;Administration -&amp;gt; License -&amp;gt; install licenses for plugin by click +&lt;/p&gt;
&lt;p&gt;Troubleshooting:&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;biserver-ee$ tail -f tomcat/logs/catalina.out
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;biserver-ee$ tail -f tomcat/logs/pentaho.log&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If the pentaho.xml is present at tomcat/conf/Catalina directory, delete it. It will be generated again when you start the BA Server.&lt;/p&gt;
&lt;p&gt;Start and stop the BI server:&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;biserver-ee$ ./start-pentaho.sh
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;biserver-ee$ ./stop-pentaho.sh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


      </content>
    </entry>
  
    <entry>
      <title>Dimensional Modeling</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/05/dimensional-modeling/"/>
      <id>https://www.endpointdev.com/blog/2013/05/dimensional-modeling/</id>
      <published>2013-05-08T00:00:00+00:00</published>
      <author>
        <name>Josh Tolley</name>
      </author>
      <content type="html">
        &lt;p&gt;People occasionally bring up the question, “What exactly is a data warehouse?” Though answers to this question vary, in short a data warehouse exists to analyze data and its behavior over large swaths of time or many different data sources. There’s more to it, though, than simply cramming historical data into the same old database. There are a number of defining characteristics, including the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query patterns and behavior&lt;/li&gt;
&lt;li&gt;Data retention policy&lt;/li&gt;
&lt;li&gt;Database structure&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;query-behavior&#34;&gt;Query Behavior&lt;/h3&gt;
&lt;p&gt;Data warehouses are sometimes called “OLAP” databases, which stands for “on-line analytical processing”, in contrast to the more common “OLTP”, or “on-line transaction processing” databases that manage data for an online storefront, a bug tracker, or a blog. A typical OLTP database supports applications that issue short, simple queries, and expect quick answers and support for many simultaneous transactions. The average OLAP query, by contrast, is generally read-only, but can be quite complex, and might take minutes or hours to complete. Such queries will often include heavy-duty statistical processing and data mining, involving terabytes of data.&lt;/p&gt;
&lt;h3 id=&#34;data-retention&#34;&gt;Data Retention&lt;/h3&gt;
&lt;p&gt;In a typical e-commerce database, eventually it becomes helpful to archive away older data that the front-end applications won’t need anymore. This helps performance, simplifies backups, and has the nice side-effect of leaving less data available for nefarious black hats that come snooping around. But it doesn’t make sense simply to discard much of this data, because it contains valuable information: customer behavior, supplier response time, etc. Often this deleted data remains alive, in a different form perhaps, in a data warehouse, which can contain data spanning many years.&lt;/p&gt;
&lt;h3 id=&#34;database-structure&#34;&gt;Database structure&lt;/h3&gt;
&lt;p&gt;Because query patterns in data warehouses differ so much from OLTP databases, it makes sense to structure the OLAP database to support its queries better. OLTP databases typically follow an “entity” model, hence the ubiquitous (if often not particularly useful) entity-relationship diagram. In such a design, tables represent objects stored in the database, such as an order, a user, or a product. OLAP databases, on the other hand, are commonly “dimensionally” modeled, which results in something called a “star schema”. In a star schema, the database contains large “fact” tables, full of foreign keys pointing to a set of “dimension” tables; when diagrammed, this looks like star with the fact table in the center, or for the more mechanically oriented, a wheel with the fact table at the hub and dimension tables at the end of each spoke. Rather than modeling a particular entity, the fact table generally describes business processes, such as customer conversion or shipping efficiency.&lt;/p&gt;
&lt;p&gt;Dimensional modeling is an interesting topic full of its own rules of thumb, which often differ quite dramatically from typical entity modeling. For instance, whereas many database modelers complain about the use of &lt;a href=&#34;https://en.wikipedia.org/wiki/Surrogate_key&#34;&gt;surrogate keys&lt;/a&gt; in OLTP databases, it’s recommended in dimensional modeling. Dimensional databases generally don’t need OUTER joins, and rarely contain NULL values. As a result, business intelligence applications designed for data warehousing can make certain assumptions about how they’ll be asked to query the database. These assumptions obviously place some limits on the types of queries the database can process effectively. However it is through these assumptions that the system gains most of its efficiency.&lt;/p&gt;
&lt;p&gt;Biggest among the limitations of an OLAP database is what’s called the “grain”. The grain describes exactly what information the fact table contains, and at what level of detail; it should be made clear during the first stages of warehouse design and widely understood by all involved. Queries that require information that isn’t part of the grain, or at finer levels of detail, must find a different fact table to use. But for queries which depend only on the available data, the fact table can be very efficient, as the database can partition it easily, and scan it unencumbered by simultaneous writes from other transactions, and filtered by simple conditions and INNER joins to the various dimension tables.&lt;/p&gt;
&lt;p&gt;Data warehouses differ from the traditional database in several other ways, but this covers some of the basics. Dimensional modeling alone is a well-developed field of study with numerous intricacies, where experience and careful training are important for developing a useful final model. But the analytical power of such databases has been proven.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>TriSano and Pentaho at our NYC company meeting</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2012/06/trisano-and-pentaho-at-our-nyc-company/"/>
      <id>https://www.endpointdev.com/blog/2012/06/trisano-and-pentaho-at-our-nyc-company/</id>
      <published>2012-06-13T00:00:00+00:00</published>
      <author>
        <name>Jon Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;Josh Tolley just spoke to us about the &lt;a href=&#34;https://web.archive.org/web/20120723110816/http://www.trisano.com/&#34;&gt;TriSano&lt;/a&gt; open source project he works on. It helps track and report on public health events, using data at least partly gathered from doctors following special legal reporting requirements to look for epidemics.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.flickr.com/photos/80083124@N08/7183675839/&#34;&gt;&lt;img alt=&#34;Josh Tolley speaking at End Point office&#34; height=&#34;375&#34; src=&#34;/blog/2012/06/trisano-and-pentaho-at-our-nyc-company/image-0.jpeg&#34; width=&#34;500&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A lot of this is about data warehousing. Public health officials collect a lot of data and want to easily report on it. Typically they use SPSS. Need to filter the data before doing analysis.&lt;/p&gt;
&lt;p&gt;And what is a data warehouse? Store all your data in a different way that’s efficient for querying broken down by time (OLAP). Such queries don’t usually work very well in normal transactional (OLTP) database.&lt;/p&gt;
&lt;p&gt;Dimension tables: E.g. different public health departments, sex, disease. Fact tables: Contains the numbers, facts that you may do math aggregation against, and links to dimension tables. The key to the whole process is deciding what you want to track.&lt;/p&gt;
&lt;p&gt;Pentaho is what we use for the query interface. To get done what we need to do, we have to make use of unpublished APIs, using JRuby to interface between Pentaho (Java) and TriSano, a Rails app. Postgres is the database.&lt;/p&gt;
&lt;p&gt;Brian Buchalter then took over and delved more into the TriSano Rails side of the project.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.flickr.com/photos/80083124@N08/7368955894/&#34;&gt;&lt;img alt=&#34;Brian Buchalter speaking at End Point office&#34; height=&#34;500&#34; src=&#34;/blog/2012/06/trisano-and-pentaho-at-our-nyc-company/image-1.jpeg&#34; width=&#34;375&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let’s talk about the challenge of maintaining Rails applications. Getting them to work today is fine. Getting them to be flexible and change over time is a challenge. The early benefit of Rails was organizational: Having empty directories to put things into. But starting to use standard classic object oriented patterns is finally happening more in Rails.&lt;/p&gt;
&lt;p&gt;Brian recommended Sandi Metz’s &lt;a href=&#34;https://vimeo.com/26330100&#34;&gt;talk about the path to better design&lt;/a&gt;, and her upcoming book, &lt;a href=&#34;https://www.amazon.com/Practical-Object-Oriented-Design-Ruby/dp/0321721330&#34;&gt;Practical Object Oriented Design in Ruby&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ruby lets you open a class anytime, anywhere, and do whatever you want to it: “monkey patching.” For example, plugins hijacking public methods. It can cause trouble. He strongly recommends watching the video &lt;a href=&#34;https://www.youtube.com/watch?v=NftT6HWFgq0&#34;&gt;Capability vs. Suitability by Gary Bernhardt&lt;/a&gt;, presented at MountainWest Ruby Conf 2012.&lt;/p&gt;
&lt;p&gt;Practical limits unveil over time as people customize in ways you don’t expect. For example, a 1300-question form that takes 4 minutes to load. Add arbitrary limits up front so that people understand there’s a design limit rather than a “bug” of bad performance or UI due to unforeseen use cases.&lt;/p&gt;
&lt;p&gt;Software is supposed to be easy to change. That’s what people like, and that’s what our employment is all about. But antipatterns emerge that make change harder over time.&lt;/p&gt;
&lt;p&gt;How do we work with our clients when there’s technical debt accumulated that will make further development increasingly expensive and troublesome? How do we estimate with imperfect information? Important to keep yourself from losing focus by diving into implementation details.&lt;/p&gt;
&lt;p&gt;If you see part of your app that needs to be implemented but has no classes, just helper calls, double your estimate.&lt;/p&gt;
&lt;p&gt;If you see lots of conditional blocks in your code, double your estimate. All the additional logic paths greatly increase complexity and make it harder to test.&lt;/p&gt;
&lt;p&gt;Don’t Repeat Yourself (DRY) is of course needed. But refactoring code is not (just) about removing duplication: It’s about making code easier to modify forever.&lt;/p&gt;
&lt;p&gt;Refactoring needs to be built into the development cycle, or else we end up forever dealing with first-implementation code, simply moving on to the next project.&lt;/p&gt;
&lt;p&gt;Comprehensive tests that take 75 minutes to run won’t get run by developers very often! The project automatically runs tests on check-in, but getting the result back takes too long. Would be good to speed up tests.&lt;/p&gt;
&lt;p&gt;Lots of good topics to follow up on here.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Spring authentication plugin</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2012/02/spring-authentication-plugin/"/>
      <id>https://www.endpointdev.com/blog/2012/02/spring-authentication-plugin/</id>
      <published>2012-02-24T00:00:00+00:00</published>
      <author>
        <name>Josh Tolley</name>
      </author>
      <content type="html">
        &lt;p&gt;One of our clients regularly deploys &lt;a href=&#34;http://www.pentaho.com/&#34;&gt;Pentaho&lt;/a&gt; with their application, and wanted their users to be able to log in to both applications with the same credentials. We could, of course, have copied the user information from one application to another, but Pentaho, and the Spring system it uses for authentication, allows us to be much more elegant.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.springsource.org/&#34;&gt;Spring&lt;/a&gt; is often described as an “application development framework”, or sometimes an &lt;a href=&#34;http://en.wikipedia.org/wiki/Spring_Framework&#34;&gt;“Inversion of Control container”&lt;/a&gt;, which essentially means that you can redefine, at run time, exactly which objects perform various services within your application. That you have to navigate a bewildering and tangled web of configuration files in order to achieve this lofty goal, and that those files suffer from all the verbosity you’d expect from the combined forces of XML and Java, normally isn’t as loudly proclaimed. Those inconveniences notwithstanding, Spring can let you do some pretty powerful stuff, like in our case, redefining exactly how a user gets authenticated by implementing a few classes and reciting the proper incantation in the configuration files.&lt;/p&gt;
&lt;p&gt;Spring handles most of the plumbing in the Pentaho authentication process, and it all starts with this particular definition from one of the Spring configuration files:&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/1902255.js&#34;&gt; &lt;/script&gt;
&lt;p&gt;The authenticationManager bean contains a list of authentication processors, and here’s where our custom code begins. These beans must implement the &lt;a href=&#34;http://static.springsource.org/spring-security/site/docs/3.1.x/apidocs/org/springframework/security/authentication/AuthenticationProvider.html&#34;&gt;Spring AuthenticationProvider interface&lt;/a&gt;, and to customize the authentication we can just put a new bean in this list. The list is ordered; refer to the &lt;a href=&#34;http://static.springsource.org/spring-security/site/docs/3.1.x/apidocs/org/springframework/security/authentication/ProviderManager.html&#34;&gt;ProviderManager&lt;/a&gt; documentation for details, but essentially any of the beans in the list can accept a set of credentials. Here, we’ve simply added a reference to our new bean, to the beginning of the list. The new bean is indicated by name only; it needs to be defined elsewhere, like this:&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/1902423.js&#34;&gt; &lt;/script&gt;
&lt;p&gt;Here we’ve mapped the bean name to a specific class name. We can also add whatever configuration properties we need. So long as there are corresponding setter methods in the actual code (e.g. “public void setProperty_1(String value)”) these will Just Work. Along with these setter methods, we must implement the two methods in Spring’s AuthenticationProvider interface. The most important is the aptly-named &lt;a href=&#34;http://static.springsource.org/spring-security/site/docs/3.1.x/apidocs/org/springframework/security/authentication/AuthenticationProvider.html#authenticate(org.springframework.security.core.Authentication)&#34;&gt;authenticate()&lt;/a&gt;, which Spring will call when a user tries to log in.&lt;/p&gt;
&lt;p&gt;authenticate() gets one argument, an Authentication object, and when a user presents valid credentials, that’s also what it returns. The first thing our new implementation needs to do is get the username and password from the authentication object:&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/1902398.js&#34;&gt; &lt;/script&gt;
&lt;p&gt;At this point we’ve got two jobs to do: first, validate the credentials, and second (assuming the credentials are valid), determine what roles the user should be given. In this particular case we used the authentication database from the client’s application to validate the credentials; that code will be completely different from one bean to the next, so I won’t share it here, but the second part, finding the user’s roles, is pretty consistent. Spring lets you set up as many roles as you’d like, giving each a different text name, and simply assumes all the different roles will mean something to the application (Pentaho, in this case) later on. For our setup, we look up the user’s roles from a database, and then tell Spring about them like this:&lt;/p&gt;
&lt;script src=&#34;https://gist.github.com/1902541.js&#34;&gt; &lt;/script&gt;
&lt;p&gt;At this point, the user has successfully logged in. If we didn’t want to allow the user in, we could instead throw an AuthenticationException, and Spring would go on to next AuthenticationProvider in the list. The beauty of it all is now that I have a working plugin, I can modify my application’s authentication system simply by modifying a configuration file or two (or three) and restarting the application.&lt;/p&gt;

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