<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dickson Tan</title>
    <description>The latest articles on DEV Community by Dickson Tan (@neurrone).</description>
    <link>https://dev.to/neurrone</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F383956%2F3faad310-55d4-4723-b086-e754a2fb3cf9.png</url>
      <title>DEV Community: Dickson Tan</title>
      <link>https://dev.to/neurrone</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/neurrone"/>
    <language>en</language>
    <item>
      <title>Automating Sprint Review Slides with Pandoc</title>
      <dc:creator>Dickson Tan</dc:creator>
      <pubDate>Fri, 12 Jun 2020 13:51:45 +0000</pubDate>
      <link>https://dev.to/mcf/automating-sprint-review-slides-with-pandoc-383b</link>
      <guid>https://dev.to/mcf/automating-sprint-review-slides-with-pandoc-383b</guid>
      <description>&lt;p&gt;In the MyCareersFuture team, we conduct sprint reviews at the end of the sprint to showcase what the team has achieved. We use PowerPoint slides to highlight stories that have been done and those which are still being worked on. Preparing this by hand was time-consuming. Here's how we automated the process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Getting Story Data&lt;/li&gt;
&lt;li&gt;Generating PowerPoint Slides&lt;/li&gt;
&lt;li&gt;Customizing Appearance of Generated Slides&lt;/li&gt;
&lt;li&gt;Limitations&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Story Data &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We use Pivotal Tracker for project management. The Pivotal Tracker API returns stories in the current iteration or sprint via the &lt;a href="https://www.pivotaltracker.com/help/api/rest/v5#projects_project_id_iterations_get"&gt;&lt;code&gt;/projects/{project_id}/iterations?scope=current_backlog&amp;amp;limit=1&lt;/code&gt;&lt;/a&gt; API call. The response looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"finish"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2020-05-19T00:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"iteration"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2020-05-04T00:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stories"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"story"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;563&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2020-05-19T12:01:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"updated_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2020-05-19T12:01:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"estimate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"story_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"feature"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Complete construction of the Expeditionary Battle Planetoid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Palpatine was impressed with the PoC, make this one bigger"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"current_state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"accepted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;lots&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;more&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;story&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;stories&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sprint&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Generating PowerPoint Slides &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Programmatically generating a PowerPoint file isn't for the faint of heart even in a language that has a library for the task. This is where Pandoc comes to the rescue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pandoc.org/"&gt;Pandoc&lt;/a&gt; is an open source tool that converts between almost any markup format that you can think of, including from markdown to PowerPoint. By using the Pivotal API, I wrote a tool that outputs markdown source which Pandoc then converts into the actual slides. Here's what the markdown might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sprint&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;63"&lt;/span&gt;
&lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;18 Sep - 02 Oct&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gu"&gt;## Sprint backlog - Done!&lt;/span&gt;

&lt;span class="ge"&gt;*Jobseeker*&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; Create a service/API to serve constants to all other modules (5 points)
&lt;span class="p"&gt;*&lt;/span&gt; change redux code to Typescript for ui-jobseeker
&lt;span class="p"&gt;*&lt;/span&gt; Populate the content placeholder on the category landing page with the html content (batch 2)
&lt;span class="p"&gt;*&lt;/span&gt; Implement page title and meta description for category landing page (batch 2)
&lt;span class="p"&gt;*&lt;/span&gt; Revise content piece, page title and meta description for Risk Management category landing page 

&lt;span class="ge"&gt;*Employer*&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; Add "Employers Toolkit" link in Employer navbar

&lt;span class="gu"&gt;## Jobseeker - In Progress Features&lt;/span&gt;

&lt;span class="ge"&gt;*Delivered*&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; Implement VDP link for MCF jobseeker and make changes to footer

&lt;span class="ge"&gt;*Finished*&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; Implement GA tracking on the recommended jobs on the application confirmation page
&lt;span class="p"&gt;*&lt;/span&gt; Switch to MCF figures for application count of all jobs
&lt;span class="p"&gt;*&lt;/span&gt; Include "Search term" in recommender API
&lt;span class="p"&gt;*&lt;/span&gt; Implement recommended jobs on JD page (getting the jobs from DSAID API)
&lt;span class="p"&gt;*&lt;/span&gt; Implement data science tracking for view JD page
&lt;span class="p"&gt;*&lt;/span&gt; Set up company profile page
&lt;span class="p"&gt;*&lt;/span&gt; Implement data science tracking for the jobs returned on each page of the search page

&lt;span class="ge"&gt;*Started*&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; Change copy for government scheme section on JD page and search results page
&lt;span class="p"&gt;*&lt;/span&gt; Implement recommended jobs on JD page (frontend)
&lt;span class="p"&gt;*&lt;/span&gt; Company profile page - jobs section
&lt;span class="p"&gt;*&lt;/span&gt; Company profile page - About the company section
&lt;span class="p"&gt;*&lt;/span&gt; Company profile page meta description
&lt;span class="p"&gt;*&lt;/span&gt; Take contact number and email address from MCF instead of MySF 

&lt;span class="gu"&gt;## Jobseeker - In Progress Chores&lt;/span&gt;

&lt;span class="ge"&gt;*Started*&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; Improve stability of job application tests
&lt;span class="p"&gt;*&lt;/span&gt; Jobseeker: Cypress Tests for GA calls
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Saving that to a file named &lt;code&gt;presentation.md&lt;/code&gt;, the following Pandoc invocation generates &lt;code&gt;presentation.pptx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;pandoc presentation.md &lt;span class="nt"&gt;-o&lt;/span&gt; presentation.pptx &lt;span class="nt"&gt;--self-contained&lt;/span&gt; &lt;span class="nt"&gt;--reference-doc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;template.pptx &lt;span class="nt"&gt;--slide-level&lt;/span&gt; 2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When there is too much content to fit into a slide or if ad hoc changes need to be made, the generated markdown and PowerPoint file can be edited afterwards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7VjKm3NB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://neurrone.com/images/sprint%252063%2520title%2520slide.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7VjKm3NB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://neurrone.com/images/sprint%252063%2520title%2520slide.png" alt="Sprint 63 Title Slide with a main title of Sprint 63 and subtitle 18 Sep - 02 Oct"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ItM1tIfv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://neurrone.com/images/sprint%252063%2520done%2520stories.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ItM1tIfv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://neurrone.com/images/sprint%252063%2520done%2520stories.png" alt="Sprint 63 slide for done stories. Refer to the markdown source above for its contents"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R0O8V-Ts--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://neurrone.com/images/sprint%252063%2520jobseeker%2520in%2520progress%2520features.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R0O8V-Ts--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://neurrone.com/images/sprint%252063%2520jobseeker%2520in%2520progress%2520features.png" alt="Sprint 63 slide for in-progress Jobseeker feature stories. Refer to the markdown source above for its contents"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The references to "Jobseeker" and "Employer" are the 2 squads in MCF which implement the jobseeker and employer facing portions of the product respectively.&lt;/p&gt;

&lt;p&gt;Here's how markdown's semantics naturally map to slides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lines 2 and 3 in the source above specify metadata about the document, title and date in this case. This is part of Pandoc's support for front matter and causes a title slide to be generated with this information.&lt;/li&gt;
&lt;li&gt;Pandoc was configured to use a slide level of 2. Hence, the level 2 headings are used as slide titles of new slides.&lt;/li&gt;
&lt;li&gt;Text between level 2 headings appear on slides as content. Any markdown formatting there such as lists and emphasis causes the corresponding formatting changes in the output.&lt;/li&gt;
&lt;li&gt;A line with 3 consecutive dashes (&lt;code&gt;---&lt;/code&gt;) causes a new slide to begin after that point. This isn't used in the example above but is very useful when content needs to be split between slides without creating a title for each slide. Refer to &lt;a href="https://pandoc.org/MANUAL.html#producing-slide-shows-with-pandoc"&gt;Pandoc's user guide&lt;/a&gt; for other directives to insert pauses, incremental lists and speaker notes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Customizing Appearance of Generated Slides &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;--reference-doc=template.pptx&lt;/code&gt; argument instructs Pandoc to use a PowerPoint template which provides some control over layout and formatting. Although Pandoc technically supports using your own templates, Pandoc crashed often when I tried doing so&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. Hence, I recommend exporting a copy of Pandoc's default PowerPoint template and using it as a starting point for customization with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# writes Pandoc's default PowerPoint template to template.pptx&lt;/span&gt;
pandoc &lt;span class="nt"&gt;-o&lt;/span&gt; template.pptx &lt;span class="nt"&gt;--print-default-data-file&lt;/span&gt; reference.pptx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Open this file in PowerPoint and under the view ribbon, activate slide master view.&lt;/p&gt;

&lt;p&gt;The first slide is the master slide. Changing the formatting of the title and text at various list levels applies the corresponding formatting when used to generate slides, a poor man's CSS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IJESdeub--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://neurrone.com/images/slide%2520master.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IJESdeub--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://neurrone.com/images/slide%2520master.png" alt="The Slide Master for our sprint review slides, which lets you adjust formatting for slide titles and text in list levels 1 through 6"&gt;&lt;/a&gt;&lt;br&gt;Here's the Slide Master for our sprint review slides set to use the Arial font instead of the default Calibri. Notice how this matches with the content slides above.
  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qxU6tdor--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://neurrone.com/images/title%2520slide.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qxU6tdor--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://neurrone.com/images/title%2520slide.png" alt="The title slide for our sprint review slides. It can have its main title, subtitle and date placeholder fields customized"&gt;&lt;/a&gt;&lt;br&gt;Similarly, here's our Title Slide layout.
  &lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The format of content was kept as simple as possible - essentially a title and content in lists. Pandoc's PowerPoint writer technically supports a 2-column layout and the use of tables. However, we ran into issues because we could not adequately customize the formatting applied to our needs. For instance, each column in a table could not have different widths causing text to often go offscreen.&lt;/p&gt;

&lt;p&gt;Besides PowerPoint, Pandoc also supports creating PDF slides via LaTeX and HTML5 slides via Slideous, Slidy, DZSlides or reveal.js. These formats allow virtually full customization of the generated slides, including the use of JavaScript and CSS for HTML5 presentations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We've been automating most of the preparation for our sprint review slides this way for almost a year now, saving an hour each sprint. If you're preparing slides with information from a system that exposes an API or prefer the text editor like I do, I highly recommend trying Pandoc out.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;this seems to happen if the template file is not compatible with the set of XML directives Pandoc recognizes for PowerPoint files. For example, Pandoc wouldn't accept the template file from a set of slides prepared with Google Slides. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>automation</category>
      <category>markdown</category>
      <category>pandoc</category>
      <category>presentations</category>
    </item>
  </channel>
</rss>
