.gitignore000066400000000000000000000003611516165077600130640ustar00rootroot00000000000000/build /node_modules /*.log .idea/workspace.xml .idea/tasks.xml .idea/profiles_settings.xml .idea/inspectionProfiles/Project_Default.xml .idea/inspectionProfiles/profiles_settings.xml node_modules/.yarn-integrity package-lock.json /release.idea/000077500000000000000000000000001516165077600120545ustar00rootroot00000000000000.idea/codeStyleSettings.xml000066400000000000000000000004251516165077600162530ustar00rootroot00000000000000 .idea/html-pdf.iml000066400000000000000000000005201516165077600142670ustar00rootroot00000000000000 .idea/misc.xml000066400000000000000000000006111516165077600135270ustar00rootroot00000000000000 true false true .idea/modules.xml000066400000000000000000000004141516165077600142450ustar00rootroot00000000000000 .idea/php.xml000066400000000000000000000004441516165077600133670ustar00rootroot00000000000000 .idea/vcs.xml000066400000000000000000000002471516165077600133740ustar00rootroot00000000000000 .npmignore000066400000000000000000000002321516165077600130700ustar00rootroot00000000000000/.idea /artifacts /build /test /node_modules /*.iml /*.ipr /*.iws /.travis.yml /.scrutinizer.yml /Gruntfile.js /*.lock *.log /corifeus-boot.json /release.scrutinizer.yml000066400000000000000000000010071516165077600142540ustar00rootroot00000000000000checks: javascript: true filter: excluded_paths: - test/* - node_modules/* - build/* - docs/* build: cache: disabled: true environment: google_chrome: use_latest: true dependencies: before: - export LATEST=$(nvm ls-remote | tail -1) - nvm install $LATEST # - nvm use $LATEST - npm install -g grunt-cli tests: override: - command: 'grunt' coverage: file: 'build/coverage/clover.xml' format: 'clover' .travis.yml000066400000000000000000000001221516165077600132000ustar00rootroot00000000000000language: node_js node_js: - "node" before_script: - npm install grunt-cli -g Gruntfile.js000066400000000000000000000004541516165077600133740ustar00rootroot00000000000000module.exports = (grunt) => { const builder = require(`corifeus-builder`); const loader = new builder.loader(grunt); loader.js({ replacer: { type: 'p3x', npmio: true, }, }); grunt.registerTask('default', builder.config.task.build.js); };LICENSE000066400000000000000000000021571516165077600121060ustar00rootroot00000000000000MIT License Copyright (c) 2017 Luigi Pinca / Patrik Laszlo / patrikx3 / https://patrikx3.com and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. README.md000066400000000000000000000055231516165077600123600ustar00rootroot00000000000000[//]: #@corifeus-header [![Build Status](https://travis-ci.org/patrikx3/html-pdf.svg?branch=master)](https://travis-ci.org/patrikx3/html-pdf) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/patrikx3/html-pdf/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/patrikx3/html-pdf/?branch=master) [![Code Coverage](https://scrutinizer-ci.com/g/patrikx3/html-pdf/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/patrikx3/html-pdf/?branch=master) [![NPM](https://nodei.co/npm/p3x-html-pdf.png?downloads=true&downloadRank=true&stars=true)](https://www.npmjs.com/package/p3x-html-pdf/) --- # Generates PDF from HTML with custom headers and footers with wkhtmltopdf v1.2.36-115 This is an open source project. Just code. If you like this code, please add a star in GitHub and you really like, you can donate as well. Thanks you so much! Given, I have my own server, with dynamic IP address, it could happen that the server for about max 5 minutes can not be reachable for the dynamic DNS or very rarely I backup with Clonzilla the SSD or something with the electricity (too much hoovering or cleaning - but I worked on it, so should not happen again), but for some reason, it is not reachable please hang on for 5-30 minutes and it will be back for sure. All my domains (patrikx3.com and corifeus.com) could have errors right now, since I am developing in my free time and you can catch glitches, but usually it is stable (imagine updating everything always, which is weird). ### Node Version Requirement ``` >=8.9.0 ``` ### Built on Node ``` v9.3.0 ``` The ```async``` and ```await``` keywords are required. Install NodeJs: https://nodejs.org/en/download/package-manager/ undefined # Description [//]: #@corifeus-header:end Generates PDF from HTML with custom headers and footers with wkhtmltopdf # First version Since, the basic installation, we need scripts to startup the library: ```bash yarn install p3x-html-pdf ``` Soon, it will work with OSX as well. It is a ```microservice``` that I created for my job with Sygnus. Given of the amount of code I write, sometimes it takes to write documentation. [//]: #@corifeus-footer --- [**P3X-HTML-PDF**](https://pages.corifeus.com/html-pdf) Build v1.2.36-115 [![Like Corifeus @ Facebook](https://img.shields.io/badge/LIKE-Corifeus-3b5998.svg)](https://www.facebook.com/corifeus.software) [![Donate for Corifeus / P3X](https://img.shields.io/badge/Donate-Corifeus-003087.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=LFRV89WPRMMVE&lc=HU&item_name=Patrik%20Laszlo&item_number=patrikx3¤cy_code=HUF&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted) [![Contact Corifeus / P3X](https://img.shields.io/badge/Contact-P3X-ff9900.svg)](https://www.patrikx3.com/en/front/contact) [//]: #@corifeus-footer:endhtml-pdf.iml000066400000000000000000000005171516165077600133150ustar00rootroot00000000000000 package.json000066400000000000000000000023111516165077600133570ustar00rootroot00000000000000{ "name": "p3x-html-pdf", "version": "1.2.36-115", "corifeus": { "prefix": "p3x-", "publish": true, "type": "p3x", "code": "WwkHtmlTox", "nodejs": "v9.3.0" }, "license": "MIT", "description": "Generates PDF from HTML with custom headers and footers with wkhtmltopdf", "main": "src/index.js", "directories": { "test": "test" }, "scripts": { "test": "grunt", "install": "node src/package/install.js" }, "repository": { "type": "git", "url": "git+https://github.com/patrikx3/html-pdf.git" }, "keywords": [ "html", "pdf", "async", "header", "custom", "footer" ], "author": "Patrik Laszlo ", "bugs": { "url": "https://github.com/patrikx3/html-pdf/issues" }, "homepage": "https://pages.corifeus.com/html-pdf", "devDependencies": { "corifeus-builder": "^1.7.1098-259" }, "dependencies": { "cheerio": "^1.0.0-rc.2", "corifeus-utils": "^1.1.735-254", "fs-extra": "^5.0.0", "progress": "^2.0.0" }, "engines": { "node": ">=8.9.0" } }src/000077500000000000000000000000001516165077600116635ustar00rootroot00000000000000src/base.html000066400000000000000000000006021516165077600134610ustar00rootroot00000000000000 ${settings.html} src/header-footer.html000066400000000000000000000025061516165077600153000ustar00rootroot00000000000000 src/index.js000066400000000000000000000155231516165077600133360ustar00rootroot00000000000000const utils = require('corifeus-utils'); const path = require('path'); const fs = require('mz/fs'); const fsExtra = require('fs-extra'); const template = require('lodash/template'); const cleanDeep = require('lodash/cloneDeep'); const cheerio = require('cheerio') const startCase = require('lodash/startCase'); const os = require('os'); const isWin = os.platform() === 'win32'; const binPathAddon = isWin ? '' : 'wkhtmltox/'; const binpath = path.resolve(`${__dirname}/../release/${binPathAddon}bin/wkhtmltopdf`); const generate = async (options) => { const {settings, saveFile, base, debug, title} = options; const isFixed = () => { return settings.template.fixedWidth > 0 && settings.template.fixedHeight } const save = settings.hasOwnProperty('save') && settings.save === true; // const consoleDebugOriginal = console.debug; if (debug) { console.debug = console.info; } else { console.debug = () => {}; } let tmpHtmlPath; let tmpPdfPath; let tmpHtmlPathFooter; let tmpHtmlPathHeader; try { const baseHtml = (await fs.readFile(`${__dirname}/base.html`)).toString(); const baseHtmlFooterHeader = (await fs.readFile(`${__dirname}/header-footer.html`)).toString(); let html = template(baseHtml)(options) let $ = cheerio.load(html); const $id = $('[id]'); let header = {} let footer = {}; const defaultHeightMargin = '10mm'; let marginTop= defaultHeightMargin ; let marginBottom = defaultHeightMargin ; $id.each((index, element) => { const $element = $(element) const $parent = $element.parent(); // console.debug($parent.html()); const id = $element.attr('id'); if (id.startsWith('p3x-header')) { header[id] = $parent.html(); marginTop = $element.data('height') || defaultHeightMargin ; $element.remove(); } else if (id.startsWith('p3x-footer')) { footer[id] = $parent.html(); marginBottom = $element.data('height') || defaultHeightMargin ; $element.remove(); } }) // console.debug('marginTop', marginTop); // console.debug('marginBottom', marginBottom); /* page: frompage: topage: = pages webpage: section: subsection: date: isodate: time: title: doctitle: sitepage: sitepages: */ $('ngivr-html-template-include .p3x-header').remove(); $('ngivr-html-template-include .p3x-footer').remove(); html = $.html(); html = html.replace(/\${qr}/g, options.settings.qr) const headerOrFooter = (data, type) => { const lodashTemplateHack = ` item = item.replace(/\\$\{page}/g, vars.page); item = item.replace(/\\$\{pages}/g, vars.pages); item = item.replace(/\\$\{qr}/g, qr); `; const mainsSettings = cleanDeep(options) mainsSettings.settings.html = JSON.stringify(data, null, 2); data = template(baseHtmlFooterHeader)(mainsSettings) data = data.replace('// headerOrFooter //', `var headerOrFooter = ${type};`) data = data.replace('// lodash-template-hack //', lodashTemplateHack) data = data.replace('// qr-hack //', ` var qr = ${JSON.stringify(mainsSettings.settings.qr)}; `) return { mainSettings: mainsSettings, data: data } } const headResult = headerOrFooter(header, 1) // const headerSettings = headResult.mainSettings; header = headResult.data; const footResult = headerOrFooter(footer, 2) // const footerSettings = footResult.mainSettings; footer = footResult.data; // console.debug('headerSettings', headerSettings) // console.debug('footerSettings', footerSettings) // console.debug('html', html) // console.debug('header', header) tmpHtmlPath = await utils.fs.ensureTempFile(html, 'html') tmpHtmlPathHeader = await utils.fs.ensureTempFile(header, 'html') tmpHtmlPathFooter = await utils.fs.ensureTempFile(footer, 'html') tmpPdfPath = await utils.fs.tempFileName('pdf'); // console.debug('footer', footer) // console.debug('tmpHtmlPath', tmpHtmlPath); // console.debug('tmpPdfPath', tmpPdfPath); // --header-html ${tmpHtmlPath} --footer-html ${tmpHtmlPath} /* -B, --margin-bottom Set the page bottom margin -L, --margin-left Set the page left margin (default 10mm) -R, --margin-right Set the page right margin (default 10mm) -T, --margin-top Set the page top margin */ // // let addOn = ''; if (isFixed()) { marginTop = '0mm'; marginBottom = '0mm'; addOn += ` --margin-left 0mm --margin-right 0mm` } const pageSize = isFixed() ? `--page-width ${settings.template.fixedWidth}mm --page-height ${settings.template.fixedHeight}mm` : `--page-size ${settings.template.format}`; const generatePdfCommand = `${binpath} --javascript-delay 1000 --copies ${settings.template.copies} --margin-bottom ${marginBottom} --margin-top ${marginTop} ${addOn} ${debug ? '--debug-javascript' : ''} --title ${JSON.stringify(title + ' ' + new Date().toLocaleString( ))} --orientation ${startCase(settings.template.orientation)} ${pageSize} ${tmpHtmlPath} --header-html ${tmpHtmlPathHeader} --footer-html ${tmpHtmlPathFooter} ${tmpPdfPath}`; console.debug('generatePdfCommand', generatePdfCommand); await utils.childProcess.exec(generatePdfCommand, debug); if (save) { await fsExtra.move(tmpPdfPath, saveFile) } else { return fs.readFile(tmpPdfPath); } } finally { if (tmpHtmlPath !== undefined) { await fsExtra.remove(tmpHtmlPath); } if (tmpHtmlPathFooter !== undefined) { await fsExtra.remove(tmpHtmlPathFooter); } if (tmpHtmlPathHeader !== undefined) { await fsExtra.remove(tmpHtmlPathHeader); } if (!save && tmpPdfPath !== undefined) { await fsExtra.remove(tmpPdfPath); } // console.debug = consoleDebugOriginal; } } module.exports.generate = generate;src/package/000077500000000000000000000000001516165077600132565ustar00rootroot00000000000000src/package/install.js000066400000000000000000000067031516165077600152700ustar00rootroot00000000000000const utils = require('corifeus-utils'); const os = require('os'); const path = require('path'); const fsExtra = require('fs-extra'); // https://api.github.com/repos/wkhtmltopdf/wkhtmltopdf/tags // https://api.github.com/repos/wkhtmltopdf/wkhtmltopdf/releases/latest const progress = require('progress'); const currentRelease = 'https://api.github.com/repos/wkhtmltopdf/wkhtmltopdf/releases/latest'; const install = async() => { const binPath = path.resolve(`${__dirname}/../../release`); await fsExtra.remove(binPath); const arch = os.arch(); const platform = os.platform() let platformSearch; let archSearch; if (platform === 'linux') { platformSearch = 'linux'; if (arch === 'x64') { archSearch = 'amd64'; } } else if (platform === 'win32' && arch === 'x64') { // wkhtmltox-0.12.4_mingw-w64-cross-win64.exe platformSearch = 'mingw-w64-cross'; archSearch = 'win64'; } if (platformSearch === undefined || archSearch === undefined) { console.log(`This platform for p3x-html-pdf is not implemented: ${platform}/${arch}`); console.log('The p3x-html-pdf will not work, but will work silently'); return } console.log(`Found platform: ${platformSearch} and architecture ${archSearch}`); console.log(`Downloading latest release for wkhtmltopdf`); const { body } = await utils.http.request(currentRelease); const findReleaseAsset = body.assets.find((asset) => { return asset.browser_download_url.includes(platformSearch) && asset.browser_download_url.includes(archSearch); }) if (findReleaseAsset === undefined || findReleaseAsset === null) { throw new Error('Could not found the latest release for wkhtmltopdf') } console.log(`Found the latest release: ${findReleaseAsset.browser_download_url}`); await utils.fs.ensureDir(binPath); const releaseBinaryFileName = `${binPath}/${path.basename(findReleaseAsset.browser_download_url)}`; const downloadResponse = await utils.http.request({ url: findReleaseAsset.browser_download_url, pipe: true, }) const releaseBinaryFile = utils.fs.createWriteStream(releaseBinaryFileName); downloadResponse.pipe(releaseBinaryFile.stream); const releaseSize = downloadResponse.headers['content-length']; const bar = new progress('Downloading release [:bar] :rate/bps :percent :etas', { complete: '=', incomplete: ' ', width: 20, total: parseInt(releaseSize, 10), }); downloadResponse.on('data', (chunk) => { bar.tick(chunk.length); }) await releaseBinaryFile; if (platform === 'linux') { console.log(`Decompress ${releaseBinaryFileName}`); await utils.childProcess.exec(`tar -xvf ${releaseBinaryFileName} -C ${binPath}`, true) } else if (platformSearch === 'mingw-w64-cross') { console.log(`Install ${releaseBinaryFileName}`); const winCommand = `cmd.exe /v /c "set binpath=${binPath} && \"${releaseBinaryFileName}\" /S /D=!binpath! && echo !binpath!"`; await utils.childProcess.exec(winCommand, true) } console.log(`Delete ${releaseBinaryFileName} file`); await fsExtra.remove(releaseBinaryFileName) /* const jqueryVersion = `jquery@1.12.4`; console.log(`Install The specific ${jqueryVersion} we need`); await utils.childProcess.exec(`npm install ${jqueryVersion}`); */ console.log(`Install done`); } install();test/000077500000000000000000000000001516165077600120535ustar00rootroot00000000000000test/fixtures/000077500000000000000000000000001516165077600137245ustar00rootroot00000000000000test/fixtures/footer.html000066400000000000000000000035031516165077600161110ustar00rootroot00000000000000
Page of
test/fixtures/header.html000066400000000000000000000034401516165077600160430ustar00rootroot00000000000000 test/fixtures/ngivr-html-template/000077500000000000000000000000001516165077600176245ustar00rootroot00000000000000test/fixtures/ngivr-html-template/ngivr-html-template.css000066400000000000000000000020671516165077600242430ustar00rootroot00000000000000.ngivr-button-row-left { padding-right: 5px; } .ngivr-position-fixed-top-left { position: fixed; top: 0px; left: 0px; } .ngivr-position-fixed-top-right { position: fixed; top: 0px; right: 0px; } .ngivr-position-fixed-bottom-left { position: fixed; bottom: 0px; left: 0px; } .ngivr-position-fixed-bottom-right { position: fixed; bottom: 0px; right: 0px; } /** template .template { // > 600 // <= 600 @media screen and (min-width: $screen-small) { } // <= 960 @media screen and (min-width: $screen-medium) { } // <= 1280 @media screen and (min-width: $screen-large) { } // <= 1920 @media screen and (min-width: $screen-huge) { } } */ body { font-size: 20px; } #pageHeader-first { height: 1cm; } #pageHeader { height: 1cm; } .ngivr-template-page-break { height: 1px; border-top-style: dotted; page-break-after: always; } .ngivr-html-template-error { color: white; background-color: red; padding: 5px; font-size: 15px; } ngivr-html-template-include { background-color: rgba(128, 128, 128, 0.5); } test/fixtures/ngivr-html-template/sygnus-logo.png000066400000000000000000001117041516165077600226240ustar00rootroot00000000000000PNG  IHDR^3ļ pHYs.#.#x?v OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-;iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2017-05-22T14:18:03+02:00 2017-05-22T14:43:50+02:00 2017-05-22T14:43:50+02:00 image/png 3 sRGB IEC61966-2.1 xmp.iid:867dad6f-296b-5c4f-acac-5ab6fcaa8e1f xmp.did:4ac6bd16-7352-7744-8cd9-0a06ab89d82c xmp.did:4ac6bd16-7352-7744-8cd9-0a06ab89d82c created xmp.iid:4ac6bd16-7352-7744-8cd9-0a06ab89d82c 2017-05-22T14:18:03+02:00 Adobe Photoshop CC 2017 (Windows) saved xmp.iid:22b03d36-1575-7344-84f7-35013a97eadc 2017-05-22T14:32:57+02:00 Adobe Photoshop CC 2017 (Windows) / saved xmp.iid:867dad6f-296b-5c4f-acac-5ab6fcaa8e1f 2017-05-22T14:43:50+02:00 Adobe Photoshop CC 2017 (Windows) / 1 3000000/10000 3000000/10000 2 1 350 172 t cHRMz%u0`:o_FMIDATxwTTWsgf`.Ez#vc=1V1I4FbƊ-5N "Qzm}{)3yg-J̹~>7i@h6(@@ /@ %^@ K "@9B ކW/QVVCzbk``0D"Ӈt @VVVR#d(..L&#A rI5mmm K "@@ Dx /@ ^@ K "@@ Dx /@ ^@ K "@@ Dx /@ ^@ K "@@ Dx /@ ^@ K "@@ Dx /@ ^@ K "opp@QߵA4hB`ѳE(¿VxeVP@.W]$\.x<\.\.+Ќp*zߟiH$hiiA.CPB }ˈ-rTVVCJJ r hժLLL`kk gggj x^\.d2RRRo>tcƌH$"/@/a-JDB Ddd$ U4cR8|XYY{\RD)L&CLL ^|Ǐzzz  /#R ĹsPXXZ.Q*"55>>>A1c 888@,`o޼={Xa.++ӷL 2~\Q\\۷oc޽TŦPS<~֘={6v }}}x[ 3V\333066ɓѧO ;;;vP p8D ‡'VUU!66ϯSp%:t[[[CKK REEE$iؽ{7i\vO-@`í@DD.].j---xzzb022b7ɘ11rHKKÅ R,JZ@6)LBEE}:AVr98 1el߾rI,/@ L;z(JJJH/ߦB4d2kvM_LF"‡!K!%%;-Wкukk㭱/χ8P/W"A > eݻw˲T(޽;tuuֱ.W.ёu;@ |rA4222Yoɉ`ėSNx -EA"ŋ sM0cmmm;Zds@ xeuf{"6/a~*'d^B<;2(B*6u)AQlll0zZ] K Z2bccوmT@ `0TTT%-d ^BhsYfffpssa+@ Z޽{IQv؁L`kfmܸqZds@ XeX K.E~~~Or077҄A!M).ˑ+V͛7H$ dt/drx?XT~_B}ְIjH⅗&@cRIΞ=^D"EQ~+:::ȗC[[ב(//݋ׯ_/SG]0! 0{l7&@ hx޽Z,ED?f̘7nugS   6 #FW @h(j3m߾=]VW@yy9֮] kkk,\... [$cΰBHf Dx-^E]vjo$#Ѿ}{@ k3Bp8 Bx\.Zjccc} ///ś Bam"##IIIFQQR)Dhݺ5akk w^x5k1JJJW^!##UUU)kkk ;;;@WWlڴ ?~|ˡPlK|TUU8u;)޷o_xyyp8jqA4cccܹspuuذa`hh(5MӨd'I&[n FXX ==zo0* fBǎ֗ BHHpL|rhkk߿? :%lll~:H@P޽;qm۶b1J C*B"`ܹòeh!X HԠ͊ A& >[ne >L( 888om}>|g"((XbWٳ'F77mdh߾=zcǎ5 8>:uJS۷/fϞ P(> *";;[Q(Bee%(~5Xxq%j$ׇGgΜٳgS̳d6W mmmv? 77BHH[nakk HIIږ?=dҫMƍh߾ZIii)._ !H !jiEQD())_|+++\pBr.#rfff b\t}eee&z{d2t޽իW֭[Jca&$''ܹsر#FO?JXx1RVYYY6oތ۷o7UkX[[CKKlKC-^<\r%Zܹs''',4Myyyp=ܿ_e°a $''k׮z;'ǔ<|N³gXHQ`mm;wOj#55ׯ_ի!HXw3n&O m۶s͛FYYY\_}}222ﭭu W-BEE{]6m...055 99y&{T ---t yyyHLLMX`.]~4HNN̙39ax򂥥%b6׆Yce۶mصk+>ROn}3f tVZaÆ >|tR\~}%h1g5Kp18q}f0ӯVVV @ u9˗9R)v(Γ'OfJP`֬YX~}3V˗ixzzb>;v,P(000_VGeɗi`ժU󳉉8}4?Bcw}e˖OZ44Y ńB!|>"""}μ\8wlmm!! eWGG o)'|sssjY VZ!P^^[nK4p|jOHH<==orXjmۆv5* Æ '|yFIt8)S@GGҥ ڷo.U=ÄG wEzz:@ ȑ# N֭3ǫt]b8qB-ϟ?G||<,YҨIݻ+y---q 4蝟744D1qD#::VwgϞS>@QF޾jZQuaԩ~:JKKeksm SLaWuC5 dDW^ZL4 J/^|gaһwo\~ʀi6ݱ~v7mf:tHc_~8::ȨQ8p NP[n2uƎ.C6/Y딦iϯ.9ر6lhrj(Z0007{}P( QUUuag7H>6l@6mTl8Y?& cp\ԩS6Sjqq_iñiӦZǟ6VZǏkefffM*mNk׮Eyy0c ]I'g5f1bkmm)ߧ1988EEE۷YV.?F[n/?={ڗ.]¢E(Oܹsj$ǏNiBaw>c'yU.L &5A~~>@t6 kݗ+Cn.fLjժvZZN>4bڴiMnی3t |>uf-SREaժU믑nd׃K!3E!""wQ}7ŏQ999ajnBBMƧqFLJx<^~땕Q_k;ikkMqU%S}U4Btܹp`o߾j3֯_Xܨ* 'ЩS'l޼I9!( bڴi{.l /pppPB!M$m?vRڹsV3gά14^zaʔ)ҟ;wƔ)S@thc^GFFQحl%&4N 4j\*,?^jո0[]tx0IpV\C}w]kT\.… v~f͚.]+V@\\R?3V-[?.]&Djhd]KB2 ؽ{F u-zzzHJJjp_02 %sQ]= 3:PP@ C8pA_'wYXjM.]_kpƍ&g߾}O8ʕ+(9rDeĉz0i$ǫe5 ˗/goL&ٳ@UCzSVV4n)BJJ z!C4x@5wg0>֭[cժUXd;JzHNNQTTbŗbǎ*6EQڵk}~}Nnnnj;wMDEEv ҟNNN066V 3fқ?>$.U$ 1`ڗK|?zzz+ X2|w(deealzSk++*zB4N,gϞ8|0̙Z֭[D† T.y<aÆz_qP޽{cĉjk+VmˏikZhݺ5&lƏ~ j?W̼ߥ5k֭[ݷnoaou9fll'رc9r{=&m׮]jV,Nػw/^|<|ϟg]+۷oW _e AN"0h lݺUf# j cEA*bΝ3f =z{4(RQeVVVq1vsRGbb{}ٴijlq8d2̛7d2xyyE5,<~_V9yq8%>}: ߌL09#5y.7c9k|řqX[[vvvXd |}}ѫWf@.sشiʃ\.ϟ?k둗Bm۪O>˅l۶ {V"&QΤ mx<rXdJK*::W{ۢj^5JKرc044T)\.=R[ӧN>VZ՚/?Ap/yQl'p6mÇ7kÇ[tرCexfU .ӧk$9Mrrr KbLԩv OOuqrJk"C ۷1|Z4EQr|2nܸ!CnT4 /s688#;Ju+B(m۶ظq#qF]iFZZQ1L4 Oq&)b L22 k֬\.vڥ(--UYYib!Э[7׈as'uvN:5)x]Ǿ}T.{r9OGuD9Հ^ ]^AGG4Mӱdɒ&2♗ בyuH$BNo>,_jB@ee%Tv}gvɱ˖-?H[W5kKT c#447~'B1{K.Ezz:.\={o߾{VFUkCee%>$ԭWs_>}@&Pc4N.?İap+^6 D1b,` a``aÆח]Ssrr>mݺ5vءs\9rNÁFOM1i%k3DR熇XhfϞ&vW5z쉅 6k]vF$ YfT31ejժ^șq ,@qq޷_ 5)VuXx1֯_yyyٳJapvZFhkkTC"%_js\lZZZX,OL\;wԚ70gӧOwrW^<++K&abx}mmm/jPضm[ ɓ5U=/4^%:U3HCƁXIjƍ'JLMMqF\pM\3{5jTR|jT )•+W \֔3G~q}?$ᵷŋU|>ƌ6@,RZZZ.LMMUcYJ(|RVtݻwӧ_~]ś7o0jԨz:Ը޻wY JǻwnF i׮JkfaiiYkTD"Qkn`iiYïDh[C1~x<3nܸF&69Hi Νիa``PgT1kj{^B6Ax<)7Ɓ$JKKk檭ծ]:>I|IYYYj̮uKx[lA׮]kmQ_tKIz_τ(xyyݻ5kK|o޼or\?~U\"2 ߿? RԩSGiF\\\XeԂBÉ'`bb=|>5rommZwW|b8q#^'5r111HIIa70އ4 }}}|7􌍍pZLAA(L:񐞞ެkܒ000o={pqb1|qޜ(eee#V|ٳgGxx8 /3Й _+uvvX,nP;(jh ךIH}EQoѵkW߿_D,;W!*HgöS eO>!^p]t5!UEE߿rvxV/5 D"QZ~HL4_y.Eڵkd%ѣGc*ǜ.RSSL'''M@ c+4Ri |QQ4ɓ*#`}߿235kP\\^ Hx<6%W(1b84ÇҲbjo#F!rBr=r?b{M4 @EEEӴj rQQQjoX,ƁTƠs\dee e5e_hqC& @m|/^VL&#i`߾}L&p\[m<[[! PM @@РwE45>WWW۫4&ޥp( vBrr{u94OE4~'), gܸqڵ---TT+633S0I٦MBQ%:''l%6m4Z j,C 1*wN* |>=ٺ9.\zO ...xUׯ\.Wٗ B#%-`޽simm]#4(d}y*++A4/ô9..iTB;;#?28; %%%גۛ-=Nt k֬Qy,"..Nm޵V+V21<^6/ȑ#qQ5Z2 GH;U)( q^F|_|u5r\d2$&&"ʄt<O#-W]ߧd޼yl[U5ܹs1qzh,:tO>ERRƾߵkc4 ?xۚ FFFӧO^f /|˅-..޽{i27mĦLP}eXR\ɩƳ( UUU7nRRR>~.))QJyf <OcXd |wp8dظqFyA. Ǐoisee%[wUzh̙3yVndN͝;iiil\uZJܹsIIIrlذmڴQ(--U)r\z@ s`mmr⫨_|*-,,dYR]?~[9;;cԩ5%&&b(++BH$/O?vBVVWAT\L2>Dyy98x<^Cc(ǃD"ALL n|9ݻwg] r$CNNJ{mkժ_={8NLQ222憻w]l\0HYYFFOOlڵpqqQ?-?? $ځ`nnB4N8e˖5Rpp06mڤ$>>>:"jKRp\Xn؟R>ZNϞ=)|>}ܹs\zXxxxǏ{b1Ο?y(pPZZiӦ[-y޽2&YJ1:.:w p88z(LMMėIQ9o|8߿ߨbڴil[~?~kR-E  OOO"--=2񠥥>Ǻ$<|>ZZZ0;;… 2r8p .] HVx"=zTkD;vEuŊ8z(6 f&8p{TTTTn m333ï SS=""'OdBf˸6vz-o^Ν;+eNߏAa*SNa?~<_^ai>h7_~%땛:!!K.ŬY HrvwXti'i2;;^3GNN+v6k:| 8cǎD"kW^T&x!?S6L)ٳgcĉQΝ;044d oj ٘G@YVKYO<cǎEΝY@ x/\$ 9?J,JP(`nnwwwtppp;n3ݻwXgڵ1qz%bL&EZZ.][֨G41g 0ƐH$XéSΝ;/{n^ ˖-ٳgYmK.XHIIAtt4R)yB;bÆ ֭Zڻ}vlݺrzEll, {d2P[[[t]v9|>R)̌r/4𖔔x  f***>c}Ǐ#<</^@RR$ü\.fڵ3zݻ7ʥgΜA^^] ؉뫔 5\"##qmjY› ///Vx\.k.nZi)P( PZZd={!!!M!2#{cC509OĂH$EQ011 LMMk tttlgLdCQD" `hh>[xYo7@FFbccQRRrBNNNTK4b2>լU,pﲄeD,L:vvvJQ D#K jC-^D8q"BCCaddcҒo #:::% <<{ kT*:th۶-XR] /cr8t 022;-J0Ԧ( zzzŰ~R"++ Faa!Ô600add===D"(2@ kM6h׮kQ6CA. mڴQ^㾨ʴ%* ^u?ncŮ3eՖϖF#-\ciaVZUU;B9H$5jfyݭJlx: ͛75zgϞܹs vIR\|jmOYY|}}LgI4&WTT(ur@?]vaŊjOd2MoPטs^IQd(**¹sUhBí[ѣG :=z@ii)n߾ ǣW^5jW7HZ >رc1tP͛7X|9._ ccj ƍ_~jk׭[oCvZ@6#\]]1|p'Op<=z4FUT?.^!Cرcw}  ! P\\ CCCt4Mc޼yj}ϟ?ի\ڵ [nO?Ԩ̄zqlٲ8ulll%4###7zBPPbcc1o}Ï?Xp8aԩ ATTO$6x"^z/SL!YYYXh>sL>߇.!JӨ WWWСCؿ?v sss^j;v,47kϭ>' Dew"-C wS&LW6Ԍ&'!C Tի M{f#iIVtzAԩ]vJ[r%LLLO?Te3g@.k׮,[y<1z2UVnݪ(r~~>d2/===DFFbӦMݻw 5~7cƌF|Vg+{`-Ʀ^իWv^x xyy ?~:f̘T={GErr2d2f͚ZV 7oDPPD"`oo~՚666III(((>3w8<^z]]]̙3GQ׋/P(ׯbi.]K)1ٴTPgVo^^nܸHQFd2mk֬#GQkiXӧdؾ};ѣG$&&bp8%[[znݺӧ>}:ݫT]vd(++@ BǃJJJ`eeN:/_Daa!&OAŋHKKCAAUNyy9|||{{{K.prrBUU_\br033Cee%Zh/_D@@$ 0aoߞYY^ CCC :[lW_}ź~Znz›7om X3}:vXеkװdOF߾}J1b֬YsaӦM8t V ( >6lR? AЧO9r?C)$1sLښT_BOO k*| mۆC;v@AAA l޽ظq#ڵk777:tCUd,\,]ӧOq%ܹ# 6ʕ+˱h"Z>ĉhѢzGsrb|ر.\Gj]fRLHH`~@ee%:tj}:{俠| 222c۶mu oLL ;f "xyyA*bȑ p=ӧO1o<ŋBvv6<==1k,'#www<CeΝ ;w[l;{E :VVV0agϞ:ʢ_zE5_~~>GߺunAAA%=zhzȐ!U>Dwؑ~---N:~5=o<Ғ3gK9s>~8-yuFGtnn.M4mmmM_xWɓ'Ri-,,  ҥ v܉1c@,?èӧP^^333"DWWAUUk-[г#&&033>o DGGGʕ+pz`bbt)Y l^r;v-[9sŋؾ};>S%֭[_гgOv5ǏL&cqkkk}enj3b=zR|>***~̙3Z[0c 8::bǎ͛*?/ѽ{wPm۲mdb/xMк!CѣGxiFǎfxxx͛0aΞ=[璒Tui}% ry0P###6L&ŋA4Z|9V^~믿ƬYХK Á^Ct&4ž={@4Pĭ\}i KKKbc'l0/G&ȍ䨬DYY6mڵ r;9՚R)… 1fڵ gΜ?q)PTט2e D"[*<<\.VVVɓ'cڴiJBѷo_9ȑ#k.8q̙OOO 鉊 J@M9}v3>o 66 عs'F:rF"222`ffNR  88W^ȑ#>7uThiiJ1yyy( ƍZ0|B!9sY pM_? .`߾}011Q[///СC5V-9uTΝS+,zJeuP͵ Y+Wcǎ U^~R]jj*lll q̙+..Ƌ/9uT<K,L&?(A۵kW\pr&MRZ1E^^999˃*++͛wnܸwqqq*ٜL l薷7,X<)UZVVVk=Μ9/_ѣYA wŋSSSСC5)Jxc&UΝ*|JB'aܾ}DPP%1uTpFk >Ő!C2a0B!222jns-"-ڥ(J)X,>#}{vѣtuuUV:]~=/dq{J~PUU5kԈضmPQQ㧟~(b28D"HKKôiӔ9l0hiiaɒ%5Dyڵx  >??w g}b\ƄqF2QL'?UL`W} |PbMo?VС޼yS27RC]Ѹtu|ȑ#`>ݻw=qu1 @ tؑ a111Xx1yfeeeHLLDll,+)Sm|Ѯ];Ո`MڇX,FQQQ Ý;w`mm;w`С Ǐ-nܸ!C̙3tzKKKՋ-4]G}3g"998z(n޼'"""FaCL̦P(DUUk >/۷qF.] ((_`Ȑ!pvvFV0n8cҤI5oܸ ddd 00Ř5kx<ۇ3f G1l06AP< nuu?+SֆL&v tʕ4iѿ\pg޽ !3!((sbСMZZZضmkX?W^᫯=O?y$Ο?]]],^Æ ۷ocѢE8s [F’%K$蹹XlY χ>333(ݕ+Wp]X[[ 'ODnn.bbbaTUU!''OF^^b1hV_Ō33$, M8}t+z3&61 :::HNNP(sAAn޼˗/#&&H$ec>DHHJJJ˗/|>vvvpuuœ'O\z Wɓ(((@~~>_CEQQn޼7n 'OdwO<޽{1dxyy!22N“'O ahhmۢ W^Exx8޼yH+++Ƌ/n,:t$777طoBBB LLL=zG w܁vヤ$"GEhh([u)))ػw/333ݻ8u[ظq#RRRF{֭[ABB9p8Ahh(2z*RRRتǏDZcǠlTUU :::066ƥKpY4 &@GG?rSӧw>|/_ݻ_qI@&oAZZ>cʕ+ KpI9:uB=PTTgϞ!$$ϟGbb"9{{{<}˗/A4жm[! /_DFF#G **y1<kkkx{{ɓ'֭qEطoO>#G <qqqBvЦMݻ(**\.=wɓ'q%TVV"++ 000@كK*Wk꨹FICkɓ'D077L&CBBlllľ"]ʔ"''fffJWoFnn.ڴinݺǏCGGg-zt6rRRR޿aCw&88/^֭[+ٍ BAA>c6|'#''l蕵5ͬtڕxbccsxۇĕ^\ MӈDyy9lmmA4Ҡ]($$$ݩH$̄,--sXYYA[[999@ǎTxN^QQQ|g4X[[C&! /^`IT?'P %<Á!QQQ؟װEYYѣG.dhiii)>|L( xzz8hkk J>oH'''ֵ|1uO>(,,ӧO LDtҥFbxcҤIGjj*zn"ޖ!%"@@ Dx /@ IkMnM]]]Bwa›FX_9IvHIIAFFkiD"tرi›) {rtv@ |8TUUƦ^[ @ %"@@ Dx /@ ^@ %" I"IENDB`test/fixtures/ngivr.html000066400000000000000000000045351516165077600157460ustar00rootroot00000000000000
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test0
test1
test2
test3
test4
test5
test6
test7
test8
test9
test10
test11
tes12
test13
test14
test15
test16
test17
test/fixtures/test.html000066400000000000000000000000741516165077600155720ustar00rootroot00000000000000 this is a test test/scripts/000077500000000000000000000000001516165077600135425ustar00rootroot00000000000000test/scripts/ngivr.sh000077500000000000000000000004551516165077600152320ustar00rootroot00000000000000#!/usr/bin/env bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source $DIR/vars.sh rm $BUILD_PDF/ngivr.pdf || true $BIN --title NGIVR --orientation Landscape --page-size A4 $FIXTURES/ngivr.html --header-html $FIXTURES/header.html --footer-html $FIXTURES/footer.html $BUILD_PDF/ngivr.pdftest/scripts/test.sh000077500000000000000000000002551516165077600150620ustar00rootroot00000000000000#!/usr/bin/env bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source $DIR/vars.sh rm $BUILD_PDF/test.pdf || true $BIN $FIXTURES/test.html $BUILD_PDF/test.pdftest/scripts/vars.sh000077500000000000000000000004461516165077600150600ustar00rootroot00000000000000#!/usr/bin/env bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" ROOT=$DIR/../.. BIN=$ROOT/release/wkhtmltox/bin/wkhtmltopdf BUILD=$ROOT/build FIXTURES=$ROOT/test/fixtures BUILD_PDF=$BUILD/pdf mkdir -p $BUILD_PDF export ROOT export BIN export BUILD export FIXTURES export BUILD_PDF