Adds support for a EPUB version
Diff
.gitignore | 2 ++
Pandoc.php | 285 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RoboFile.php | 45 +++++++++++++++++++++++++++++++++++++++------
cover.png | 0
metadata.xml | 3 +++
template.tex | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_problems/school/H1.md | 15 ++++++++-------
7 files changed, 619 insertions(+), 15 deletions(-)
@@ -1,5 +1,7 @@
vendor/
.jekyll-metadata
_site/
*.zip
book.md
*.epub
*.html
@@ -1,0 +1,285 @@
<?php
/**
* Pandoc PHP
*
* Copyright (c) Ryan Kadwell <ryan@riaka.ca>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Naive wrapper for haskell's pandoc utility
*
* @author Ryan Kadwell <ryan@riaka.ca>
*/
class Pandoc
{
/**
* Where is the executable located
* @var string
*/
private $executable;
/**
* Where to take the content for pandoc from
* @var string
*/
private $tmpFile;
/**
* Directory to store temporary files
* @var string
*/
private $tmpDir;
/**
* List of valid input types
* @var array
*/
private $inputFormats = array(
"native",
"json",
"markdown",
"markdown_strict",
"markdown_phpextra",
"markdown_github",
"markdown_mmd",
"rst",
"mediawiki",
"docbook",
"docx",
"textile",
"html",
"latex"
);
/**
* List of valid output types
* @var array
*/
private $outputFormats = array(
"native",
"json",
"docx",
"odt",
"epub",
"epub3",
"fb2",
"html",
"html5",
"s5",
"slidy",
"slideous",
"dzslides",
"docbook",
"opendocument",
"latex",
"beamer",
"context",
"texinfo",
"man",
"markdown",
"markdown_strict",
"markdown_phpextra",
"markdown_github",
"markdown_mmd",
"plain",
"rst",
"mediawiki",
"textile",
"rtf",
"org",
"asciidoc"
);
/**
* Setup path to the pandoc binary
*
* @param string $executable Path to the pandoc executable
* @param string $tmpDir Path to where we want to store temporary files
*/
public function __construct($executable = null, $tmpDir = null)
{
if ( ! $tmpDir) {
$tmpDir = sys_get_temp_dir();
}
if ( ! file_exists($tmpDir)) {
throw new Exception(
sprintf('The directory %s does not exist!', $tmpDir)
);
}
if ( ! is_writable($tmpDir)) {
throw new Exception(
sprintf('Unable to write to the directory %s!', $tmpDir)
);
}
$this->tmpDir = $tmpDir;
$this->tmpFile = sprintf("%s/%s", $this->tmpDir, uniqid("pandoc"));
// Since we can not validate that the command that they give us is
// *really* pandoc we will just check that its something.
// If the provide no path to pandoc we will try to find it on our own
if ( ! $executable) {
exec('which pandoc', $output, $returnVar);
if ($returnVar === 0) {
$this->executable = $output[0];
} else {
throw new Exception('Unable to locate pandoc');
}
} else {
$this->executable = $executable;
}
if ( ! is_executable($this->executable)) {
throw new Exception('Pandoc executable is not executable');
}
}
/**
* Run the conversion from one type to another
*
* @param string $from The type we are converting from
* @param string $to The type we want to convert the document to
*
* @return string
*/
public function convert($content, $from, $to)
{
if ( ! in_array($from, $this->inputFormats)) {
throw new Exception(
sprintf('%s is not a valid input format for pandoc', $from)
);
}
if ( ! in_array($to, $this->outputFormats)) {
throw new Exception(
sprintf('%s is not a valid output format for pandoc', $to)
);
}
file_put_contents($this->tmpFile, $content);
$command = sprintf(
'%s --from=%s --to=%s %s',
$this->executable,
$from,
$to,
$this->tmpFile
);
exec(escapeshellcmd($command), $output);
return implode("\n", $output);
}
/**
* Run the pandoc command with specific options.
*
* Provides more control over what happens. You simply pass an array of
* key value pairs of the command options omitting the -- from the start.
* If you want to pass a command that takes no argument you set its value
* to null.
*
* @param string $content The content to run the command on
* @param array $options The options to use
*
* @return string The returned content
*/
public function runWith($content, $options)
{
$commandOptions = array();
$extFilesFormat = array(
'docx',
'odt',
'epub',
'fb2',
'pdf'
);
$extFilesHtmlSlide = array(
's5',
'slidy',
'dzslides',
'slideous'
);
foreach ($options as $key => $value) {
if ($key == 'to' && in_array($value, $extFilesFormat)) {
$commandOptions[] = '-s -o '.$this->tmpFile.'.'.$value;
$format = $value;
continue;
} else if ($key == 'to' && in_array($value, $extFilesHtmlSlide)) {
$commandOptions[] = '-s -t '.$value.'+smart -o '.$this->tmpFile.'.html';
$format = 'html';
continue;
} else if ($key == 'to' && $value == 'epub3') {
$commandOptions[] = '-t epub+smart -o '.$this->tmpFile.'.epub';
$format = 'epub';
continue;
} else if ($key == 'to' && $value == 'beamer') {
$commandOptions[] = '-s -t beamer+smart -o '.$this->tmpFile.'.pdf';
$format = 'pdf';
continue;
} else if ($key == 'to' && $value == 'latex') {
$commandOptions[] = '-s -o '.$this->tmpFile.'.tex';
$format = 'tex';
continue;
} else if ($key == 'to' && $value == 'rst') {
$commandOptions[] = '-s -t rst --toc -o '.$this->tmpFile.'.text';
$format = 'text';
continue;
} else if ($key == 'to' && $value == 'rtf') {
$commandOptions[] = '-s -o '.$this->tmpFile.'.'.$value;
$format = $value;
continue;
} else if ($key == 'to' && $value == 'docbook') {
$commandOptions[] = '-s -t docbook+smart -o '.$this->tmpFile.'.db';
$format = 'db';
continue;
} else if ($key == 'to' && $value == 'context') {
$commandOptions[] = '-s -t context+smart -o '.$this->tmpFile.'.tex';
$format = 'tex';
continue;
} else if ($key == 'to' && $value == 'asciidoc') {
$commandOptions[] = '-s -t asciidoc+smart -o '.$this->tmpFile.'.txt';
$format = 'txt';
continue;
}
if (null === $value) {
$commandOptions[] = "--$key";
continue;
}
$commandOptions[] = "--$key=$value";
}
file_put_contents($this->tmpFile, $content);
chmod($this->tmpFile, 0777);
$command = sprintf(
"%s %s %s",
$this->executable,
implode(' ', $commandOptions),
$this->tmpFile
);
exec(escapeshellcmd($command), $output, $returnval);
if($returnval === 0)
{
if (isset($format)) {
return file_get_contents($this->tmpFile.'.'.$format);
} else {
return implode("\n", $output);
}
}else
{
throw new Exception(
sprintf('Pandoc could not convert successfully, error code: %s. Tried to run the following command: %s', $returnval, $command)
);
}
}
/**
* Remove the temporary files that were created
*/
public function __destruct()
{
if (file_exists($this->tmpFile)) {
@unlink($this->tmpFile);
}
foreach (glob($this->tmpFile.'*') as $filename) {
@unlink($filename);
}
}
/**
* Return that path where we are storing temporary files
* @return string
*/
public function getTmpDir()
{
return $this->tmpDir;
}
}
@@ -5,6 +5,8 @@
use KzykHys\FrontMatter\FrontMatter;
use League\HTMLToMarkdown\HtmlConverter;
require ('Pandoc.php');
class RoboFile extends \Robo\Tasks
{
const ALL = 'all';
@@ -142,26 +144,53 @@
return false;
}
public function generateBook() {
$bookContent = "# CodeChef Problem\n";
private function _generateSingleHtmlFile() {
$bookContent = "<html><head><title>CodeChef Problem</title><base href='https://www.codechef.com'></head>\n";
$categories = $this->setCategories(self::ALL);
foreach ($categories as $category) {
$bookContent .= "## Category: $category\n";
$bookContent .= "<h1>Category: $category</h1>";
$problems = json_decode(file_get_contents("_data/$category.json"));
foreach ($problems as $problem) {
$file = "_problems/$category/$problem.md";
$file = "_problems/$category/$problem.json";
if (file_exists($file)) {
$document = FrontMatter::parse(file_get_contents($file));
$content = $document->getContent();
$document = json_decode(file_get_contents($file), true);
$content = $document['body'];
$bookContent .= $content . "\n\\newpage";
$bookContent .= "<h2>" . $document['problem_code'] . "</h2>";
$content = strip_tags($content, '<p><a><b><i><br><h2><h3><h1><h4><pre>');
$bookContent .= $content;
}
}
}
return $bookContent;
}
file_put_contents("book.md", $bookContent);
private function _runPandocEPUB($html) {
$pandoc = new Pandoc();
$options = [
"from" => "html",
"to" => "epub",
// "css" => "/assets/css/documents.css",
"toc" => null,
"toc-depth" => 2,
"epub-metadata" => "metadata.xml",
"epub-cover-image" => "cover.png",
"variable" => 'title:"CodeChef - The Problems"'
];
return $pandoc->runWith($html, $options);
}
public function generateBook() {
$html = $this->_generateSingleHtmlFile();
$this->say("HTML generated");
$epub = $this->_runPandocEPUB($html);
file_put_contents('codechef.epub', $epub);
}
public function generateCollection($category = self::ALL) {
Binary files /dev/null and a/cover.png differ
@@ -1,0 +1,3 @@
<dc:language>en-US</dc:language>
<dc:title id="epub-title-1">CodeChef: The Problems</dc:title>
<dc:date>2018-06-15</dc:date>
@@ -1,0 +1,284 @@
\documentclass[$if(fontsize)$$fontsize$,$endif$$if(lang)$$babel-lang$,$endif$$if(papersize)$$papersize$,$endif$$for(classoption)$$classoption$$sep$,$endfor$]{$documentclass$}
$if(fontfamily)$
\usepackage[$fontfamilyoptions$]{$fontfamily$}
$else$
\usepackage{lmodern}
$endif$
$if(linestretch)$
\usepackage{setspace}
\setstretch{$linestretch$}
$endif$
\usepackage{amssymb,amsmath}
\usepackage{ifxetex,ifluatex}
\usepackage{fixltx2e}
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0
\usepackage[$if(fontenc)$$fontenc$$else$T1$endif$]{fontenc}
\usepackage[utf8]{inputenc}
$if(euro)$
\usepackage{eurosym}
$endif$
\else
\ifxetex
\usepackage{mathspec}
\else
\usepackage{fontspec}
\fi
\defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
\newcommand{\euro}{€}
$if(mainfont)$
\setmainfont[$mainfontoptions$]{$mainfont$}
$endif$
$if(sansfont)$
\setsansfont[$sansfontoptions$]{$sansfont$}
$endif$
$if(monofont)$
\setmonofont[Mapping=tex-ansi$if(monofontoptions)$,$monofontoptions$$endif$]{$monofont$}
$endif$
$if(mathfont)$
\setmathfont(Digits,Latin,Greek)[$mathfontoptions$]{$mathfont$}
$endif$
$if(CJKmainfont)$
\usepackage{xeCJK}
\setCJKmainfont[$CJKoptions$]{$CJKmainfont$}
$endif$
\fi
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
\IfFileExists{microtype.sty}{
\usepackage{microtype}
\UseMicrotypeSet[protrusion]{basicmath}
}{}
$if(geometry)$
\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
$endif$
\usepackage{hyperref}
\PassOptionsToPackage{usenames,dvipsnames}{color}
\hypersetup{breaklinks=true,
unicode=true,
$if(title-meta)$
pdftitle={$title-meta$},
$endif$
$if(author-meta)$
pdfauthor={$author-meta$},
$endif$
$if(subtitle)$
pdfsubject={$subtitle$},
$endif$
$if(keywords)$
pdfkeywords={$keywords$},
$endif$
pagebackref,
bookmarksopen,
bookmarksnumbered,
colorlinks=true,
citecolor=$if(citecolor)$$citecolor$$else$black$endif$,
urlcolor=$if(urlcolor)$$urlcolor$$else$black$endif$,
linkcolor=$if(linkcolor)$$linkcolor$$else$black$endif$,
pdfborder={0 0 0}
$if(hidelinks)$,hidelinks$endif$}
\urlstyle{same}
$if(lang)$
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0
\usepackage[shorthands=off,$for(babel-otherlangs)$$babel-otherlangs$$sep$,$endfor$,main=$babel-lang$]{babel}
$babel-newcommands$
\else
\usepackage{polyglossia}
\setmainlanguage[$polyglossia-lang.options$]{$polyglossia-lang.name$}
$for(polyglossia-otherlangs)$
\setotherlanguage[$polyglossia-otherlangs.options$]{$polyglossia-otherlangs.name$}
$endfor$
\fi
$endif$
$if(natbib)$
\usepackage{natbib}
\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$}
$endif$
$if(biblatex)$
\usepackage{biblatex}
$for(bibliography)$
\addbibresource{$bibliography$}
$endfor$
$endif$
$if(listings)$
\usepackage{listings}
$endif$
$if(lhs)$
\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
$endif$
$if(highlighting-macros)$
$highlighting-macros$
$endif$
$if(verbatim-in-note)$
\usepackage{fancyvrb}
\VerbatimFootnotes
$endif$
$if(tables)$
\usepackage{longtable,booktabs}
$endif$
$if(graphics)$
\usepackage{graphicx,grffile}
\makeatletter
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
\makeatother
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
$endif$
$if(links-as-notes)$
\renewcommand{\href}[2]{#2\footnote{\url{#1}}}
$endif$
$if(strikeout)$
\usepackage[normalem]{ulem}
\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
$endif$
$if(indent)$
$else$
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}
$endif$
\setlength{\emergencystretch}{3em}
\providecommand{\tightlist}{
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
$if(numbersections)$
\setcounter{secnumdepth}{5}
$else$
\setcounter{secnumdepth}{0}
$endif$
$if(dir)$
\ifxetex
$if(latex-dir-rtl)$
\usepackage[RTLdocument]{bidi}
$else$
\usepackage{bidi}
$endif$
\fi
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0
\TeXXeTstate=1
\newcommand{\RL}[1]{\beginR #1\endR}
\newcommand{\LR}[1]{\beginL #1\endL}
\newenvironment{RTL}{\beginR}{\endR}
\newenvironment{LTR}{\beginL}{\endL}
\fi
$endif$
$if(title)$
\title{$title$$if(subtitle)$\\\vspace{0.5em}{\large $subtitle$}$endif$}
$endif$
$if(author)$
\author{$for(author)$$author$$sep$ \and $endfor$}
$endif$
\date{$date$}
$for(header-includes)$
$header-includes$
$endfor$
$if(subparagraph)$
$else$
\ifx\paragraph\undefined\else
\let\oldparagraph\paragraph
\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
\fi
\ifx\subparagraph\undefined\else
\let\oldsubparagraph\subparagraph
\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
\fi
$endif$
\begin{document}
$if(title)$
\maketitle
$endif$
$if(abstract)$
\begin{abstract}
$abstract$
\end{abstract}
$endif$
$for(include-before)$
$include-before$
$endfor$
$if(toc)$
{
\hypersetup{linkcolor=$if(toccolor)$$toccolor$$else$black$endif$}
\setcounter{tocdepth}{$toc-depth$}
\addtocontents{toc}{\protect{\pdfbookmark[0]{\contentsname}{toc}}}
\tableofcontents
}
$endif$
$if(lot)$
\listoftables
$endif$
$if(lof)$
\listoffigures
$endif$
$body$
$if(natbib)$
$if(bibliography)$
$if(biblio-title)$
$if(book-class)$
\renewcommand\bibname{$biblio-title$}
$else$
\renewcommand\refname{$biblio-title$}
$endif$
$endif$
\bibliography{$for(bibliography)$$bibliography$$sep$,$endfor$}
$endif$
$endif$
$if(biblatex)$
\printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$
$endif$
$for(include-after)$
$include-after$
$endfor$
\end{document}
@@ -64,6 +64,7 @@
is_direct_submittable: false
layout: problem
---
All submissions for this problem are available.Johnny has some difficulty memorizing the small prime numbers. So, his computer science teacher has asked him to play with the following puzzle game frequently.
The puzzle is a 3x3 board consisting of numbers from 1 to 9. The objective of the puzzle is to swap the tiles until the following final state is reached:
@@ -92,13 +93,13 @@
<b>Input:</b>
2
7 3 2
4 1 5
6 8 9
7 3 2
4 1 5
6 8 9
9 8 5
2 4 1
3 7 6
9 8 5
2 4 1
3 7 6
<b>Output:</b>
6
@@ -106,5 +107,5 @@
</pre>### Output details
The possible 6 steps in the first test case are described in the following figure:
