From c3e3d9941967fa5b307fa76ddbe632c24604fa1b Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Wed, 4 Mar 2020 10:58:08 +0000 Subject: [PATCH 01/13] =?UTF-8?q?=F0=9F=9A=A8=20ESLint=20allow=20console.e?= =?UTF-8?q?rror?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.js | 18 ++++++++++------ scripts/odp-to-json.js | 48 ------------------------------------------ 2 files changed, 12 insertions(+), 54 deletions(-) delete mode 100644 scripts/odp-to-json.js diff --git a/.eslintrc.js b/.eslintrc.js index 37cc7bb..25bb574 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,11 +2,17 @@ module.exports = { root: true, env: { es6: true, - node: true + node: true, }, - parser: "babel-eslint", - extends: ["eslint:recommended", "plugin:prettier/recommended"], + parser: 'babel-eslint', + extends: ['eslint:recommended', 'plugin:prettier/recommended'], rules: { - "prettier/prettier": "off" - } -}; \ No newline at end of file + 'prettier/prettier': 'off', + 'no-console': [ + 'error', + { + allow: ['error'], + }, + ], + }, +}; diff --git a/scripts/odp-to-json.js b/scripts/odp-to-json.js deleted file mode 100644 index 99c1976..0000000 --- a/scripts/odp-to-json.js +++ /dev/null @@ -1,48 +0,0 @@ -const path = require("path"); -const fs = require("fs"); -const decompress = require("decompress"); -const parser = require("xml2json"); -const program = require("commander"); - -async function main(input, outFile) { - const files = await decompress(path.resolve(input)); - const content = files.find(item => item.path === "content.xml"); - const json = parser.toJson(content.data); - fs.writeFileSync(outFile, JSON.stringify(JSON.parse(json), null, " "), { - encoding: "utf8" - }); -} - -program - .name("odp-to-json") - .usage( - ` - -Examples: - - $ odp-to-json ./my-presentation.odp - $ odp-to-json --out-dir=./my-presentation ./my-presentation.odp - ` - ) - .option("-o, --out-dir ", "file directory to extract to JSON to") - .command("* ") - .alias("extract") - .description("Extract the Open Presentation Document to JSON") - .action(async function(env) { - let outBasename = path.basename(env, path.extname(env)) + ".json"; - let outDir = path.join(path.resolve('.'), (program.outDir || env)); - let outFile = path.join(outDir, outBasename); - if (fs.existsSync(path.resolve(env))) { - console.log('Extracting "%s" to "%s"', env, path.resolve(outFile)); - await main(env, outFile); - } else { - console.error(` - -Could not extract presenation document, file missing. - -no such file '%s' - -`, path.resolve(env)) - } - }); -program.parse(process.argv); From 4bbef1b4ae1840ad322a6b4d0ac316b6e3c63a96 Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Wed, 4 Mar 2020 11:26:50 +0000 Subject: [PATCH 02/13] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Simplify=20Style.js?= =?UTF-8?q?=20moving=20extractArray=20to=20util?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/Style.test.js | 24 +------------------- __tests__/__snapshots__/Style.test.js.snap | 6 ----- src/Document.js | 4 +++- src/Style.js | 23 +++++-------------- src/utils.js | 26 ++++++++++++++++++---- 5 files changed, 31 insertions(+), 52 deletions(-) diff --git a/__tests__/Style.test.js b/__tests__/Style.test.js index 7077a99..9423f7a 100644 --- a/__tests__/Style.test.js +++ b/__tests__/Style.test.js @@ -2,44 +2,22 @@ import path from 'path'; import decompress from 'decompress'; import { toJson } from 'xml2json'; import Style from '../src/Style'; -import Presentation from '../src/Presentation'; describe('Style', () => { let subject; - let presentation; beforeEach(async () => { const files = await decompress( path.join(__dirname, '__fixtures__/file1.odp') ); const masterStylesFile = files.find(f => f.path === 'styles.xml'); - const contentFile = files.find(f => f.path === 'content.xml'); - presentation = new Presentation(JSON.parse(toJson(contentFile.data))); subject = new Style( - JSON.parse(toJson(masterStylesFile.data)), - presentation + JSON.parse(toJson(masterStylesFile.data)) ); }); - describe('masterPages', () => { - it('returns master styles for the presenation', () => { - expect(subject.masterPages).toMatchSnapshot(); - }); - }); - - describe('presentationPageLayouts', () => { - it('returns layouts for the presentation', () => { - expect(subject.presentationPageLayouts).toMatchSnapshot(); - }); - }); describe('namespaces', () => { it('returns the style XML namespaces for this presentation', () => { expect(subject.namespaces).toMatchSnapshot() }); }); - - describe('styles', () => { - it.skip('returns styles for the presentation slides', () => { - expect(subject.styles).toMatchSnapshot(); - }); - }); }); diff --git a/__tests__/__snapshots__/Style.test.js.snap b/__tests__/__snapshots__/Style.test.js.snap index 7fc53d6..4661761 100644 --- a/__tests__/__snapshots__/Style.test.js.snap +++ b/__tests__/__snapshots__/Style.test.js.snap @@ -1,7 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Style masterPages returns master styles for the presenation 1`] = `undefined`; - exports[`Style namespaces returns the style XML namespaces for this presentation 1`] = ` Object { "xmlns:anim": "urn:oasis:names:tc:opendocument:xmlns:animation:1.0", @@ -36,7 +34,3 @@ Object { "xmlns:xlink": "http://www.w3.org/1999/xlink", } `; - -exports[`Style presentationPageLayouts returns layouts for the presentation 1`] = `undefined`; - -exports[`Style styles returns styles for the presentation slides 1`] = `Array []`; diff --git a/src/Document.js b/src/Document.js index ed4e280..b56ae02 100644 --- a/src/Document.js +++ b/src/Document.js @@ -4,6 +4,8 @@ import decompress from 'decompress'; import EventEmitter from 'events'; import { toJson, toXml } from 'xml2json'; import { format } from 'prettier'; +import { extractArray } from './utils' + import Presentation from './Presentation'; import Style from './Style'; @@ -186,7 +188,7 @@ export default class Document extends EventEmitter { if (!this[key]) { this[key] = new Set(); } - style.extractArray(key).forEach(i => this[key].add(i)); + extractArray(style.data, key).forEach(i => this[key].add(i)); set(this.stylesDoc, key, Array.from(this[key])); } diff --git a/src/Style.js b/src/Style.js index 8e623ca..b13a840 100644 --- a/src/Style.js +++ b/src/Style.js @@ -1,21 +1,8 @@ -import { moveImageReferences, namespaces } from './utils' -import { get } from 'shvl'; +import { moveImageReferences, namespaces } from './utils'; -export default class Style{ - constructor(content, presentation, manifest) { - this.data = moveImageReferences(content, manifest) - this.namespaces = namespaces(content['office:document-styles']) - this.presentation = presentation; - this.doc; - this.styleIDs = new Set(); - } - - extractArray(key) { - let data = get(this.data, key) || []; - if (!Array.isArray(data)) { - return [data]; - } else { - return data; - } +export default class Style { + constructor(content, _, manifest) { + this.data = moveImageReferences(content, manifest); + this.namespaces = namespaces(content['office:document-styles']); } } diff --git a/src/utils.js b/src/utils.js index 98ddd89..e22ee00 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,10 +1,12 @@ +import { get } from 'shvl'; + /** * Replace images in content with references in the manifest from previous path locations * - * @param {object} data the content which needs any image references replacing - * @param {array} manifest manifest of files that are included in the document, with previous paths for lookup and replacement + * @param {object} data The content which needs any image references replacing + * @param {array} manifest Manifest of files that are included in the document, with previous paths for lookup and replacement * - * @returns {object} modified input data with any reference replaced within. + * @returns {object} Modified input data with any reference replaced within. */ export function moveImageReferences(data, manifest=[]) { let str = JSON.stringify(data); @@ -18,7 +20,7 @@ export function moveImageReferences(data, manifest=[]) { /** * Extract XML namespaces from the JSON representation of XML * - * @param {object} data the JSON representation of XML + * @param {object} data The JSON representation of XML * * @returns {object} XML namespace keys pairs */ @@ -30,4 +32,20 @@ export function namespaces(data) { } } return out; +} + +/** + * Find, extract and return an array for the given dotnotation object key. + * + * @param {object} input The object JSON representation of XML + * @param {string} key The key to find in the object + * @returns {array} Extracted array of content from the XML + */ +export function extractArray(input, key) { + let data = get(input, key) || []; + if (!Array.isArray(data)) { + return [data]; + } else { + return data; + } } \ No newline at end of file From 05bc92660c8dde896c4e60bbee7b28ac97db3ddb Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Wed, 4 Mar 2020 11:30:00 +0000 Subject: [PATCH 03/13] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20remove=20unused=20ma?= =?UTF-8?q?sterStylesIDs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/Slide.test.js | 8 ----- __tests__/__snapshots__/Slide.test.js.snap | 40 ---------------------- src/Slide.js | 23 ------------- 3 files changed, 71 deletions(-) diff --git a/__tests__/Slide.test.js b/__tests__/Slide.test.js index a3d3be1..2269cde 100644 --- a/__tests__/Slide.test.js +++ b/__tests__/Slide.test.js @@ -54,12 +54,4 @@ describe("Slide", () => { expect(actual).toMatchSnapshot() }); }); - - describe(".masterStyleIDs", () => { - it("finds all the parent id's that are required to bring across from the master Styles.xml document", () => { - const slide = new Slide(slidesFixture[0], fixture); - let subject = slide.masterStyleIDs; - expect(subject).toMatchSnapshot(); - }); - }); }); diff --git a/__tests__/__snapshots__/Slide.test.js.snap b/__tests__/__snapshots__/Slide.test.js.snap index a7e3bb0..fc0d49c 100644 --- a/__tests__/__snapshots__/Slide.test.js.snap +++ b/__tests__/__snapshots__/Slide.test.js.snap @@ -1,45 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Slide .masterStyleIDs finds all the parent id's that are required to bring across from the master Styles.xml document 1`] = ` -Object { - "style:list-style-name": Set { - "L4", - }, - "style:name": Set { - "dp2", - "gr1", - "pr1", - "pr2", - "pr3", - "pr4", - "pr5", - "pr6", - "pr7", - "pr8", - "pr9", - "pr10", - "pr11", - "P1", - "P2", - "P3", - "P4", - "P5", - "P6", - "P7", - "P8", - "P9", - "T1", - "T2", - }, - "style:parent-style-name": Set { - "prs-novelty-subtitle", - "prs-novelty-notes", - "prs-novelty-title", - "prs-novelty-outline1", - }, -} -`; - exports[`Slide .styleIDs returns the ids for the slide 1`] = ` Array [ "dp1", diff --git a/src/Slide.js b/src/Slide.js index 03c0595..6eb35d4 100644 --- a/src/Slide.js +++ b/src/Slide.js @@ -65,27 +65,4 @@ export default class Slide { return this.styleIDs.includes(item['style:name']); }); } - - get masterStyleIDs() { - let ids = {}; - const documentStyles = - get(this.originalPresentation, [ - 'office:document-content', - 'office:automatic-styles', - 'style:style', - ]) || []; - documentStyles.forEach(style => { - let keys = Object.keys(style); - keys.forEach(key => { - if (key.endsWith('style-name') || key.endsWith(':name')) { - if (!ids[key]) { - ids[key] = new Set(); - } else { - ids[key].add(style[key]); - } - } - }); - }); - return ids; - } } From 97c772e6cfb61dc73e2e022cd1359e15129afd40 Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Wed, 4 Mar 2020 11:30:31 +0000 Subject: [PATCH 04/13] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20simplify=20Slide=20c?= =?UTF-8?q?ontent=20(remove=20deep=20clone)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/Slide.test.js | 34 ++++++---------------------------- src/Slide.js | 25 ++++++++----------------- 2 files changed, 14 insertions(+), 45 deletions(-) diff --git a/__tests__/Slide.test.js b/__tests__/Slide.test.js index 2269cde..21888ce 100644 --- a/__tests__/Slide.test.js +++ b/__tests__/Slide.test.js @@ -16,42 +16,20 @@ const slidesFixture = get(fixture, [ ]); describe("Slide", () => { - describe(".content", () => { - it("copies without reference the originalContent", () => { - let originalContent = { - greet: "hello world", - deep: { thing: "original" } - }; - - const slide = new Slide(originalContent, fixture); - let actual = slide.content; - - expect(actual).toEqual(originalContent); - - actual.greet = "new world"; - actual.deep.thing = "changed"; - expect(actual).toHaveProperty("greet", "new world"); - expect(originalContent).toHaveProperty("greet", "hello world"); - - expect(actual).toHaveProperty("deep.thing", "changed"); - expect(originalContent).toHaveProperty("deep.thing", "original"); - }); - }); + let subject + beforeEach(() => { + subject = new Slide(slidesFixture[0], fixture); + }) describe(".styleIDs", () => { it("returns the ids for the slide", () => { - const slide = new Slide(slidesFixture[0], fixture); - let actual = slide.styleIDs; - expect(actual).toMatchSnapshot(); + expect(subject.styleIDs).toMatchSnapshot(); }); }); describe(".styles", () => { it("includes the styles for the given slide", () => { - const slide = new Slide(slidesFixture[0], fixture); - let actual = slide.styles; - - expect(actual).toMatchSnapshot() + expect(subject.styles).toMatchSnapshot() }); }); }); diff --git a/src/Slide.js b/src/Slide.js index 6eb35d4..a1a9c43 100644 --- a/src/Slide.js +++ b/src/Slide.js @@ -9,17 +9,8 @@ import { get } from 'shvl'; */ export default class Slide { constructor(content, presentation, manifest) { - this.originalContent = moveImageReferences(content, manifest); - this.originalPresentation = presentation; - } - - /** - * @getter - * @description deep copies the provided original content - * @returns {object} a deep copy of the original content - */ - get content() { - return JSON.parse(JSON.stringify(this.originalContent)); + this.content = moveImageReferences(content, manifest); + this.presentation = presentation; } /** @@ -30,17 +21,17 @@ export default class Slide { */ get styleIDs() { let ids = []; - ids.push(this.originalContent['draw:style-name']); + ids.push(this.content['draw:style-name']); ['draw:frame', 'draw:custom-shape', 'draw:connector'].forEach(key => { - if (this.originalContent[key]) { - if (Array.isArray(this.originalContent[key])) { - this.originalContent[key].forEach(item => { + if (this.content[key]) { + if (Array.isArray(this.content[key])) { + this.content[key].forEach(item => { if (item['draw:style-name']) { ids.push(item['draw:style-name']); } }); } else { - ids.push(this.originalContent[key]['draw:style-name']); + ids.push(this.content[key]['draw:style-name']); } } }); @@ -56,7 +47,7 @@ export default class Slide { */ get styles() { const documentStyles = - get(this.originalPresentation, [ + get(this.presentation, [ 'office:document-content', 'office:automatic-styles', 'style:style', From 80bd9aa0f519958ce776fb04c0ba292c33350d6d Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Wed, 4 Mar 2020 11:34:29 +0000 Subject: [PATCH 05/13] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20move=20initial=20man?= =?UTF-8?q?ifestFiles=20to=20own=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/Document.test.js | 26 ++++++++++++++++++++++++++ src/Document.js | 26 +++++++++++++++----------- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/__tests__/Document.test.js b/__tests__/Document.test.js index 11b6272..c59a8c1 100644 --- a/__tests__/Document.test.js +++ b/__tests__/Document.test.js @@ -45,6 +45,32 @@ describe('Document', () => { subject = obj.subject; }); + describe('.manifestFiles', () => { + it('has a initial set of manifest files that will exist', () => { + expect(subject.manifestFiles).toContainEqual( + expect.objectContaining({ + mimeType: 'application/vnd.oasis.opendocument.presentation', + path: '/', + version: '1.2', + }) + ); + + expect(subject.manifestFiles).toContainEqual( + expect.objectContaining({ + mimeType: 'text/xml', + path: 'content.xml', + }) + ); + + expect(subject.manifestFiles).toContainEqual( + expect.objectContaining({ + mimeType: 'text/xml', + path: 'styles.xml', + }) + ); + }); + }); + describe('.mergeFile', () => { let file = path.join(__dirname, '__fixtures__/out1.odp'); afterEach(() => { diff --git a/src/Document.js b/src/Document.js index b56ae02..b2c953c 100644 --- a/src/Document.js +++ b/src/Document.js @@ -14,7 +14,20 @@ export default class Document extends EventEmitter { super({ captureRejections: true }); this.slides = []; this.files = []; - this.manifestFiles = [ + this.manifestFiles = this.manifestFilesInitial; + this.counter = 0; + this.doc = { + 'office:document-content': {}, + }; + this.stylesDoc = { + 'office:document-styles': { + 'office:version': '1.2', + }, + }; + } + + get manifestFilesInitial() { + return [ { mimeType: 'application/vnd.oasis.opendocument.presentation', path: '/', @@ -28,16 +41,7 @@ export default class Document extends EventEmitter { mimeType: 'text/xml', path: 'styles.xml', }, - ]; - this.counter = 0; - this.doc = { - 'office:document-content': {}, - }; - this.stylesDoc = { - 'office:document-styles': { - 'office:version': '1.2', - }, - }; + ] } async mergeFile(file) { From a1c28d6fcc4f81314d1e3b52695931d5b7b77982 Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Wed, 4 Mar 2020 12:35:13 +0000 Subject: [PATCH 06/13] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Presentation=20conte?= =?UTF-8?q?nt=20to=20handle=20unique=20style=20ids?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/Document.test.js | 30 +- __tests__/Presentation.test.js | 12 +- __tests__/Slide.test.js | 35 - __tests__/__snapshots__/Document.test.js.snap | 2816 +++++++++++++++++ __tests__/__snapshots__/Slide.test.js.snap | 23 - src/Document.js | 53 +- src/Presentation.js | 51 +- src/Slide.js | 59 - src/utils.js | 7 + 9 files changed, 2892 insertions(+), 194 deletions(-) delete mode 100644 __tests__/Slide.test.js delete mode 100644 __tests__/__snapshots__/Slide.test.js.snap delete mode 100644 src/Slide.js diff --git a/__tests__/Document.test.js b/__tests__/Document.test.js index c59a8c1..009b2f6 100644 --- a/__tests__/Document.test.js +++ b/__tests__/Document.test.js @@ -108,34 +108,14 @@ describe('Document', () => { }); }); - describe('.merge', () => { + describe('.mergeContent', () => { it('merges multiple presentations', () => { - let doc = new Document(); - let fixtures = [fixture1, fixture2]; - let presentations = []; - - fixtures.forEach(fixture => { - presentations.push(new Presentation(fixture)); - }); - - presentations.forEach(pres => { - doc.merge(pres); - }); + let subject = new Document(); - let slides = get( - doc.doc, - 'office:document-content.office:body.office:presentation.draw:page' - ); + subject.mergeContent(new Presentation(fixture1, 0)); + subject.mergeContent(new Presentation(fixture2, 1)); - fixtures.forEach(fixture => { - let fixtureSlides = get( - fixture, - 'office:document-content.office:body.office:presentation.draw:page' - ); - fixtureSlides.forEach(slide => { - expect(slides).toContainEqual(slide); - }); - }); + expect(subject.doc).toMatchSnapshot() }); }); diff --git a/__tests__/Presentation.test.js b/__tests__/Presentation.test.js index d173553..b347e95 100644 --- a/__tests__/Presentation.test.js +++ b/__tests__/Presentation.test.js @@ -1,20 +1,16 @@ import fs from 'fs'; import path from 'path'; import Presenation from '../src/Presentation'; -import Slide from '../src/Slide'; const fixture = JSON.parse( fs.readFileSync(path.join(__dirname, "__fixtures__/example.json")) ); describe("Presentation", () => { - describe('.slides', () => { - it('creates an array of slides', () => { - const presenation = new Presenation(fixture) - let actual = presenation.slides - - expect(actual).toBeInstanceOf(Array) - expect(actual[0]).toBeInstanceOf(Slide) + describe('.uniqueStyleIDs()', () => { + it('renames style names with a prefixed ID', () => { + let subject = new Presenation(fixture, 0) + expect(JSON.stringify(subject.data)).toContain('"text:style-name":"0-a1219"') }) }) }) \ No newline at end of file diff --git a/__tests__/Slide.test.js b/__tests__/Slide.test.js deleted file mode 100644 index 21888ce..0000000 --- a/__tests__/Slide.test.js +++ /dev/null @@ -1,35 +0,0 @@ -import fs from "fs"; -import path from "path"; -import { get } from "shvl"; - -import Slide from "../src/Slide"; - -const fixture = JSON.parse( - fs.readFileSync(path.join(__dirname, "__fixtures__/file1.json")) -); - -const slidesFixture = get(fixture, [ - "office:document-content", - "office:body", - "office:presentation", - "draw:page" -]); - -describe("Slide", () => { - let subject - beforeEach(() => { - subject = new Slide(slidesFixture[0], fixture); - }) - - describe(".styleIDs", () => { - it("returns the ids for the slide", () => { - expect(subject.styleIDs).toMatchSnapshot(); - }); - }); - - describe(".styles", () => { - it("includes the styles for the given slide", () => { - expect(subject.styles).toMatchSnapshot() - }); - }); -}); diff --git a/__tests__/__snapshots__/Document.test.js.snap b/__tests__/__snapshots__/Document.test.js.snap index 2731da3..199a908 100644 --- a/__tests__/__snapshots__/Document.test.js.snap +++ b/__tests__/__snapshots__/Document.test.js.snap @@ -1,5 +1,2821 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Document .mergeContent merges multiple presentations 1`] = ` +Object { + "office:document-content": Object { + "office:automatic-styles": Object { + "style:style": Array [ + Object { + "style:drawing-page-properties": Object { + "presentation:background-objects-visible": "true", + "presentation:background-visible": "true", + "presentation:display-date-time": "true", + "presentation:display-footer": "true", + "presentation:display-page-number": "false", + }, + "style:family": "drawing-page", + "style:name": "0-dp1", + }, + Object { + "style:drawing-page-properties": Object { + "presentation:display-date-time": "true", + "presentation:display-footer": "true", + "presentation:display-header": "true", + "presentation:display-page-number": "false", + }, + "style:family": "drawing-page", + "style:name": "0-dp2", + }, + Object { + "style:family": "graphic", + "style:graphic-properties": Object { + "style:protect": "size", + }, + "style:name": "0-gr1", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "0-L4", + "style:name": "0-pr1", + "style:parent-style-name": "prs-novelty-title", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "13.231cm", + }, + "style:name": "0-pr2", + "style:parent-style-name": "prs-novelty-subtitle", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "11.409cm", + }, + "style:name": "0-pr3", + "style:parent-style-name": "prs-novelty-notes", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "0-L4", + "style:name": "0-pr4", + "style:parent-style-name": "prs-novelty-title", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "13.231cm", + }, + "style:name": "0-pr5", + "style:parent-style-name": "prs-novelty-outline1", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "0-L4", + "style:name": "0-pr6", + "style:parent-style-name": "prs-novelty-title", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:fill-color": "#ffffff", + "fo:min-height": "13.231cm", + }, + "style:name": "0-pr7", + "style:parent-style-name": "prs-novelty-outline1", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "0-L4", + "style:name": "0-pr8", + "style:parent-style-name": "prs-novelty-title", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "0-L4", + "style:name": "0-pr9", + "style:parent-style-name": "prs-novelty-title", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "0-L4", + "style:name": "0-0-pr10", + "style:parent-style-name": "prs-novelty-title", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "0-L4", + "style:name": "0-0-pr11", + "style:parent-style-name": "prs-novelty-title", + }, + Object { + "style:family": "paragraph", + "style:name": "0-P1", + "style:paragraph-properties": Object { + "fo:margin-left": "0.6cm", + "fo:margin-right": "0cm", + "fo:text-indent": "-1cm", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "0-P2", + "style:paragraph-properties": Object { + "fo:margin-left": "1.2cm", + "fo:margin-right": "0cm", + "fo:text-align": "center", + "fo:text-indent": "-0.6cm", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "0-P3", + "style:paragraph-properties": Object { + "fo:margin-left": "1.2cm", + "fo:margin-right": "0cm", + "fo:text-align": "center", + "fo:text-indent": "-0.6cm", + }, + "style:text-properties": Object { + "fo:font-size": "32pt", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "0-P4", + "style:paragraph-properties": Object { + "fo:margin-left": "0cm", + "fo:margin-right": "0cm", + "fo:text-indent": "0cm", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "0-P5", + "style:paragraph-properties": Object { + "fo:margin-left": "1.4cm", + "fo:margin-right": "0cm", + "fo:text-indent": "-1.2cm", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "0-P6", + "style:paragraph-properties": Object { + "fo:margin-left": "0cm", + "fo:margin-right": "0cm", + "fo:text-indent": "0cm", + }, + "style:text-properties": Object { + "fo:hyphenate": "true", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "0-P7", + "style:paragraph-properties": Object { + "fo:margin-left": "1.4cm", + "fo:margin-right": "0cm", + "fo:text-indent": "-1.2cm", + }, + "style:text-properties": Object { + "fo:hyphenate": "true", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "0-P8", + "style:paragraph-properties": Object { + "fo:margin-left": "1.4cm", + "fo:margin-right": "0cm", + "fo:text-indent": "-1.2cm", + }, + "style:text-properties": Object { + "fo:hyphenate": "true", + "style:font-size-asian": "24pt", + "style:font-size-complex": "24pt", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "0-P9", + "style:paragraph-properties": Object { + "fo:margin-left": "1.4cm", + "fo:margin-right": "0cm", + "fo:text-indent": "-1.2cm", + }, + "style:text-properties": Object { + "style:font-size-asian": "24pt", + "style:font-size-complex": "24pt", + }, + }, + Object { + "style:family": "text", + "style:name": "0-T1", + "style:text-properties": Object { + "fo:font-size": "32pt", + }, + }, + Object { + "style:family": "text", + "style:name": "0-T2", + "style:text-properties": Object { + "style:font-size-asian": "24pt", + "style:font-size-complex": "24pt", + }, + }, + Object { + "style:drawing-page-properties": Object { + "draw:fill": "solid", + "draw:fill-color": "#333366", + "draw:fill-image-height": "1cm", + "draw:fill-image-width": "1cm", + "presentation:background-objects-visible": "true", + "presentation:background-visible": "true", + "presentation:display-date-time": "true", + "presentation:display-footer": "true", + "presentation:display-page-number": "false", + }, + "style:family": "drawing-page", + "style:name": "1-dp1", + }, + Object { + "style:drawing-page-properties": Object { + "presentation:display-date-time": "true", + "presentation:display-footer": "true", + "presentation:display-header": "true", + "presentation:display-page-number": "false", + }, + "style:family": "drawing-page", + "style:name": "1-dp2", + }, + Object { + "style:drawing-page-properties": Object { + "presentation:background-objects-visible": "true", + "presentation:background-visible": "true", + "presentation:display-date-time": "true", + "presentation:display-footer": "true", + "presentation:display-page-number": "false", + }, + "style:family": "drawing-page", + "style:name": "1-dp3", + }, + Object { + "style:family": "graphic", + "style:graphic-properties": Object { + "style:protect": "size", + }, + "style:name": "1-gr1", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "1-L4", + "style:name": "1-pr1", + "style:parent-style-name": "prs-strategy-title", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:fill-color": "#ffffff", + "fo:min-height": "13.231cm", + }, + "style:name": "1-pr2", + "style:parent-style-name": "prs-strategy-subtitle", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "11.409cm", + }, + "style:name": "1-pr3", + "style:parent-style-name": "prs-strategy-notes", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "1-L4", + "style:name": "1-pr4", + "style:parent-style-name": "prs-strategy-title", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:fill-color": "#ffffff", + "fo:min-height": "13.231cm", + }, + "style:name": "1-pr5", + "style:parent-style-name": "prs-strategy-outline1", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "1-L4", + "style:name": "1-pr6", + "style:parent-style-name": "prs-strategy-title", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "1-L4", + "style:name": "1-pr7", + "style:parent-style-name": "prs-strategy-title", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "1-L4", + "style:name": "1-pr8", + "style:parent-style-name": "prs-strategy-title", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "1-L4", + "style:name": "1-pr9", + "style:parent-style-name": "prs-strategy-title", + }, + Object { + "style:family": "presentation", + "style:graphic-properties": Object { + "draw:auto-grow-height": "true", + "draw:fill-color": "#ffffff", + "fo:min-height": "3.506cm", + }, + "style:list-style-name": "1-L4", + "style:name": "1-1-pr10", + "style:parent-style-name": "prs-strategy-title", + }, + Object { + "style:family": "paragraph", + "style:name": "1-P1", + "style:paragraph-properties": Object { + "fo:margin-left": "0.6cm", + "fo:margin-right": "0cm", + "fo:text-indent": "-1cm", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "1-P2", + "style:paragraph-properties": Object { + "fo:margin-left": "0.6cm", + "fo:margin-right": "0cm", + "fo:text-indent": "-0.6cm", + }, + "style:text-properties": Object { + "fo:hyphenate": "false", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "1-P3", + "style:paragraph-properties": Object { + "fo:margin-left": "0.6cm", + "fo:margin-right": "0cm", + "fo:text-indent": "-0.6cm", + }, + "style:text-properties": Object { + "fo:font-size": "32pt", + "fo:hyphenate": "false", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "1-P4", + "style:paragraph-properties": Object { + "fo:margin-left": "0cm", + "fo:margin-right": "0cm", + "fo:text-indent": "0cm", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "1-P5", + "style:paragraph-properties": Object { + "fo:margin-left": "0cm", + "fo:margin-right": "0cm", + "fo:text-indent": "0cm", + }, + "style:text-properties": Object { + "fo:hyphenate": "true", + }, + }, + Object { + "style:family": "paragraph", + "style:name": "1-P6", + "style:paragraph-properties": Object { + "fo:margin-left": "1.4cm", + "fo:margin-right": "0cm", + "fo:text-indent": "-1.2cm", + }, + "style:text-properties": Object { + "fo:hyphenate": "true", + }, + }, + Object { + "style:family": "text", + "style:name": "1-T1", + "style:text-properties": Object { + "fo:font-size": "32pt", + }, + }, + ], + "text:list-style": Array [ + Object { + "style:name": "0-L1", + "text:list-level-style-bullet": Array [ + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "1", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "0.2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "2", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "0.8cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "3", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "1.4cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "4", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "5", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "2.6cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "6", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "3.2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "7", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "3.8cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "8", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "4.4cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "9", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "5.4cm", + }, + "style:text-properties": Object { + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + "style:use-window-font-color": "true", + }, + "text:bullet-char": "●", + "text:level": "10", + }, + ], + }, + Object { + "style:name": "0-L2", + "text:list-level-style-bullet": Array [ + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "1", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "0.6cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "2", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "1.2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "3", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "1.8cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "4", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "2.4cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "5", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "3cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "6", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "3.6cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "7", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "4.2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "8", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "4.8cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "9", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "5.4cm", + }, + "style:text-properties": Object { + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + "style:use-window-font-color": "true", + }, + "text:bullet-char": "●", + "text:level": "10", + }, + ], + }, + Object { + "style:name": "0-L3", + "text:list-level-style-bullet": Array [ + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "0.2cm", + }, + "style:text-properties": Object { + "fo:color": "#99284c", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + "style:font-charset": "x-symbol", + "style:font-pitch": "variable", + "style:font-style-name": "Regular", + }, + "text:bullet-char": "", + "text:level": "1", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "1cm", + }, + "style:text-properties": Object { + "fo:color": "#99284c", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + "style:font-charset": "x-symbol", + "style:font-pitch": "variable", + "style:font-style-name": "Regular", + }, + "text:bullet-char": "", + "text:level": "2", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "1.8cm", + }, + "style:text-properties": Object { + "fo:color": "#99284c", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + "style:font-charset": "x-symbol", + "style:font-pitch": "variable", + "style:font-style-name": "Regular", + }, + "text:bullet-char": "", + "text:level": "3", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "2.6cm", + }, + "style:text-properties": Object { + "fo:color": "#99284c", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + "style:font-charset": "x-symbol", + "style:font-pitch": "variable", + "style:font-style-name": "Regular", + }, + "text:bullet-char": "", + "text:level": "4", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "3.4cm", + }, + "style:text-properties": Object { + "fo:color": "#99284c", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + "style:font-charset": "x-symbol", + "style:font-pitch": "variable", + "style:font-style-name": "Regular", + }, + "text:bullet-char": "", + "text:level": "5", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "4.2cm", + }, + "style:text-properties": Object { + "fo:color": "#99284c", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + "style:font-charset": "x-symbol", + "style:font-pitch": "variable", + "style:font-style-name": "Regular", + }, + "text:bullet-char": "", + "text:level": "6", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "5cm", + }, + "style:text-properties": Object { + "fo:color": "#99284c", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + "style:font-charset": "x-symbol", + "style:font-pitch": "variable", + "style:font-style-name": "Regular", + }, + "text:bullet-char": "", + "text:level": "7", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "5.8cm", + }, + "style:text-properties": Object { + "fo:color": "#99284c", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + "style:font-charset": "x-symbol", + "style:font-pitch": "variable", + "style:font-style-name": "Regular", + }, + "text:bullet-char": "", + "text:level": "8", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "6.6cm", + }, + "style:text-properties": Object { + "fo:color": "#99284c", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + "style:font-charset": "x-symbol", + "style:font-pitch": "variable", + "style:font-style-name": "Regular", + }, + "text:bullet-char": "", + "text:level": "9", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "5.4cm", + }, + "style:text-properties": Object { + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + "style:use-window-font-color": "true", + }, + "text:bullet-char": "●", + "text:level": "10", + }, + ], + }, + Object { + "style:name": "0-L4", + "text:list-level-style-bullet": Array [ + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "-0.4cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "1", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "0.2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "2", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "0.8cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "3", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "1.4cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "4", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "5", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "2.6cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "6", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "3.2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "7", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "3.8cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "8", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "4.4cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "9", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "5.4cm", + }, + "style:text-properties": Object { + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + "style:use-window-font-color": "true", + }, + "text:bullet-char": "●", + "text:level": "10", + }, + ], + }, + Object { + "style:name": "1-L1", + "text:list-level-style-bullet": Array [ + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "1", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "0.2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "2", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "0.8cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "3", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "1.4cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "4", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "5", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "2.6cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "6", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "3.2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "7", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "3.8cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "8", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "4.4cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "9", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "5.4cm", + }, + "style:text-properties": Object { + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + "style:use-window-font-color": "true", + }, + "text:bullet-char": "●", + "text:level": "10", + }, + ], + }, + Object { + "style:name": "1-L2", + "text:list-level-style-bullet": Array [ + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "1", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "0.6cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "2", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "1.2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "3", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "1.8cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "4", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "2.4cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "5", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "3cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "6", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "3.6cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "7", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "4.2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "8", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "4.8cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "●", + "text:level": "9", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "5.4cm", + }, + "style:text-properties": Object { + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + "style:use-window-font-color": "true", + }, + "text:bullet-char": "●", + "text:level": "10", + }, + ], + }, + Object { + "style:name": "1-L3", + "text:list-level-style-bullet": Array [ + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "0.2cm", + }, + "style:text-properties": Object { + "fo:color": "#ff9966", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + }, + "text:bullet-char": "➲", + "text:level": "1", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "1cm", + }, + "style:text-properties": Object { + "fo:color": "#ff9966", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + }, + "text:bullet-char": "●", + "text:level": "2", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "1.8cm", + }, + "style:text-properties": Object { + "fo:color": "#ff9966", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + }, + "text:bullet-char": "●", + "text:level": "3", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "2.6cm", + }, + "style:text-properties": Object { + "fo:color": "#ff9966", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + }, + "text:bullet-char": "●", + "text:level": "4", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "3.4cm", + }, + "style:text-properties": Object { + "fo:color": "#ff9966", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + }, + "text:bullet-char": "●", + "text:level": "5", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "4.2cm", + }, + "style:text-properties": Object { + "fo:color": "#ff9966", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + }, + "text:bullet-char": "●", + "text:level": "6", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "5cm", + }, + "style:text-properties": Object { + "fo:color": "#ff9966", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + }, + "text:bullet-char": "●", + "text:level": "7", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "5.8cm", + }, + "style:text-properties": Object { + "fo:color": "#ff9966", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + }, + "text:bullet-char": "●", + "text:level": "8", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1.2cm", + "text:space-before": "6.6cm", + }, + "style:text-properties": Object { + "fo:color": "#ff9966", + "fo:font-family": "StarSymbol", + "fo:font-size": "75%", + }, + "text:bullet-char": "●", + "text:level": "9", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "5.4cm", + }, + "style:text-properties": Object { + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + "style:use-window-font-color": "true", + }, + "text:bullet-char": "●", + "text:level": "10", + }, + ], + }, + Object { + "style:name": "1-L4", + "text:list-level-style-bullet": Array [ + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "-0.4cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "1", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "0.2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "2", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "0.8cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "3", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "1.4cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "4", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "5", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "2.6cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "6", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "3.2cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "7", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "3.8cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "8", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "1cm", + "text:space-before": "4.4cm", + }, + "style:text-properties": Object { + "fo:color": "#000000", + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + }, + "text:bullet-char": "", + "text:level": "9", + }, + Object { + "style:list-level-properties": Object { + "text:min-label-width": "0.6cm", + "text:space-before": "5.4cm", + }, + "style:text-properties": Object { + "fo:font-family": "StarSymbol", + "fo:font-size": "45%", + "style:use-window-font-color": "true", + }, + "text:bullet-char": "●", + "text:level": "10", + }, + ], + }, + ], + }, + "office:body": Object { + "office:presentation": Object { + "draw:page": Array [ + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "text:p": Object { + "$t": "Introducing a New Product", + "text:style-name": "0-P1", + }, + }, + "draw:text-style-name": "0-P1", + "presentation:class": "title", + "presentation:style-name": "0-pr1", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "1.943cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "text:p": Object { + "text:span": Object { + "$t": "Title", + "text:style-name": "0-T1", + }, + "text:style-name": "0-P2", + }, + }, + "draw:text-style-name": "0-P3", + "presentation:class": "subtitle", + "presentation:style-name": "0-pr2", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.384cm", + "svg:x": "2.285cm", + "svg:y": "5.938cm", + }, + ], + "draw:master-page-name": "prs-novelty", + "draw:name": "Title", + "draw:style-name": "0-dp1", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "0-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "0-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "1", + "draw:style-name": "0-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "0-dp2", + }, + "presentation:presentation-page-layout-name": "A0-L1T0", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "0.003cm", + "text:p": Object { + "$t": "Long-term Goal", + "text:style-name": "0-P1", + }, + }, + "draw:text-style-name": "0-P1", + "presentation:class": "title", + "presentation:style-name": "0-pr4", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "1.943cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "0.003cm", + "text:list": Object { + "text:list-item": Object { + "text:p": Object { + "$t": "State the intended goal", + "text:style-name": "0-P4", + }, + }, + "text:style-name": "0-L3", + }, + }, + "draw:text-style-name": "0-P5", + "presentation:class": "outline", + "presentation:style-name": "0-pr5", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.384cm", + "svg:x": "2.285cm", + "svg:y": "5.938cm", + }, + ], + "draw:master-page-name": "prs-novelty", + "draw:name": "Long-term Goal", + "draw:style-name": "0-dp1", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "0-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "0-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "2", + "draw:style-name": "0-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "0-dp2", + }, + "presentation:presentation-page-layout-name": "A0-L20-T1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "0.016cm", + "text:p": Object { + "$t": "Customer Wishes", + "text:style-name": "0-P1", + }, + }, + "draw:text-style-name": "0-P1", + "presentation:class": "title", + "presentation:style-name": "0-pr6", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "1.943cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "0.016cm", + "text:list": Object { + "text:list-item": Array [ + Object { + "text:p": Object { + "$t": "Describe customer needs and wishes", + "text:style-name": "0-P6", + }, + }, + Object { + "text:p": Object { + "$t": "Explain the requirements", + "text:style-name": "0-P6", + }, + }, + ], + "text:style-name": "0-L3", + }, + }, + "draw:text-style-name": "0-P7", + "presentation:class": "outline", + "presentation:style-name": "0-pr7", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.384cm", + "svg:x": "2.585cm", + "svg:y": "5.838cm", + }, + ], + "draw:master-page-name": "prs-novelty", + "draw:name": "Customer Wishes", + "draw:style-name": "0-dp1", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "0-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "0-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "3", + "draw:style-name": "0-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "0-dp2", + }, + "presentation:presentation-page-layout-name": "A0-L20-T1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "0.032cm", + "text:p": Object { + "text:line-break": Object {}, + "text:style-name": "0-P1", + }, + }, + "draw:text-style-name": "0-P1", + "presentation:class": "title", + "presentation:style-name": "0-pr8", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "1.943cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "text:list": Object { + "text:list-item": Array [ + Object { + "text:p": Object { + "text:span": Object { + "$t": "Describe the main attributes of the product", + "text:style-name": "0-T2", + }, + "text:style-name": "0-P6", + }, + }, + Object { + "text:p": Object { + "text:span": Object { + "$t": "Link the product attributes to fulfil customer needs", + "text:style-name": "0-T2", + }, + "text:style-name": "0-P6", + }, + }, + ], + "text:style-name": "0-L3", + }, + }, + "draw:text-style-name": "0-P8", + "presentation:class": "outline", + "presentation:style-name": "0-pr7", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.384cm", + "svg:x": "2.585cm", + "svg:y": "5.838cm", + }, + ], + "draw:master-page-name": "prs-novelty", + "draw:name": "Fulfilling Customer Needs", + "draw:style-name": "0-dp1", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "0-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "0-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "4", + "draw:style-name": "0-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "0-dp2", + }, + "presentation:presentation-page-layout-name": "A0-L20-T1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "text:p": Object { + "$t": "Cost Analysis", + "text:style-name": "0-P1", + }, + }, + "draw:text-style-name": "0-P1", + "presentation:class": "title", + "presentation:style-name": "0-pr9", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "1.943cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "text:list": Object { + "text:list-item": Array [ + Object { + "text:p": Object { + "text:span": Object { + "$t": "Indicate the financial advantages for the customer", + "text:style-name": "0-T2", + }, + "text:style-name": "0-P4", + }, + }, + Object { + "text:p": Object { + "text:span": Object { + "$t": "Compare quality and price with those of the competition", + "text:style-name": "0-T2", + }, + "text:style-name": "0-P4", + }, + }, + ], + "text:style-name": "0-L3", + }, + }, + "draw:text-style-name": "0-P9", + "presentation:class": "outline", + "presentation:style-name": "0-pr5", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.384cm", + "svg:x": "2.285cm", + "svg:y": "5.938cm", + }, + ], + "draw:master-page-name": "prs-novelty", + "draw:name": "Cost Analysis", + "draw:style-name": "0-dp1", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "0-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "0-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "5", + "draw:style-name": "0-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "0-dp2", + }, + "presentation:presentation-page-layout-name": "A0-L20-T1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "text:p": Object { + "$t": "Strengths and Advantages", + "text:style-name": "0-P1", + }, + }, + "draw:text-style-name": "0-P1", + "presentation:class": "title", + "presentation:style-name": "0-0-pr10", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "1.943cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "text:list": Object { + "text:list-item": Object { + "text:p": Object { + "$t": "Summarise the special features and advantages of the product being introduced", + "text:style-name": "0-P6", + }, + }, + "text:style-name": "0-L3", + }, + }, + "draw:text-style-name": "0-P7", + "presentation:class": "outline", + "presentation:style-name": "0-pr7", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.384cm", + "svg:x": "2.585cm", + "svg:y": "5.838cm", + }, + ], + "draw:master-page-name": "prs-novelty", + "draw:name": "Strengths and Advantages", + "draw:style-name": "0-dp1", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "0-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "0-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "6", + "draw:style-name": "0-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "0-dp2", + }, + "presentation:presentation-page-layout-name": "A0-L20-T1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "text:p": Object { + "$t": "Next Steps of Action", + "text:style-name": "0-P1", + }, + }, + "draw:text-style-name": "0-P1", + "presentation:class": "title", + "presentation:style-name": "0-0-pr11", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "1.943cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "text:list": Object { + "text:list-item": Object { + "text:p": Object { + "$t": "Explain the steps that now need to be taken", + "text:style-name": "0-P6", + }, + }, + "text:style-name": "0-L3", + }, + }, + "draw:text-style-name": "0-P7", + "presentation:class": "outline", + "presentation:style-name": "0-pr7", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.384cm", + "svg:x": "2.585cm", + "svg:y": "5.838cm", + }, + ], + "draw:master-page-name": "prs-novelty", + "draw:name": "Next Steps of Action", + "draw:style-name": "0-dp1", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "0-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "0-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "7", + "draw:style-name": "0-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "0-dp2", + }, + "presentation:presentation-page-layout-name": "A0-L20-T1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "text:p": Object { + "$t": "Recommendation of a Strategy", + "text:style-name": "1-P1", + }, + }, + "draw:text-style-name": "1-P1", + "presentation:class": "title", + "presentation:style-name": "1-pr1", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "0.325cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "10.956cm", + "text:p": Object { + "text:span": Object { + "$t": "Title", + "text:style-name": "1-T1", + }, + "text:style-name": "1-P2", + }, + }, + "draw:text-style-name": "1-P3", + "presentation:class": "subtitle", + "presentation:style-name": "1-pr2", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.548cm", + "svg:x": "3.023cm", + "svg:y": "6.178cm", + }, + ], + "draw:master-page-name": "prs-strategy", + "draw:name": "Title", + "draw:style-name": "1-dp1", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "1-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "1-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "1", + "draw:style-name": "1-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "1-dp2", + }, + "presentation:presentation-page-layout-name": "A1-L1T0", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "0.024cm", + "text:p": Object { + "$t": "Overview", + "text:style-name": "1-P1", + }, + }, + "draw:text-style-name": "1-P1", + "presentation:class": "title", + "presentation:style-name": "1-pr4", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "0.325cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "0.024cm", + "text:list": Object { + "text:list-item": Array [ + Object { + "text:p": Object { + "$t": "Summarise the main plans", + "text:style-name": "1-P5", + }, + }, + Object { + "text:p": Object { + "$t": "Explain the long-term course to follow", + "text:style-name": "1-P5", + }, + }, + ], + "text:style-name": "1-L3", + }, + }, + "draw:text-style-name": "1-P6", + "presentation:class": "outline", + "presentation:style-name": "1-pr5", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.548cm", + "svg:x": "3.023cm", + "svg:y": "6.178cm", + }, + ], + "draw:master-page-name": "prs-strategy", + "draw:name": "Overview", + "draw:style-name": "1-dp3", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "1-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "1-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "2", + "draw:style-name": "1-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "1-dp2", + }, + "presentation:presentation-page-layout-name": "A1-L21-T1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "0.032cm", + "text:p": Object { + "$t": "Long-term goal", + "text:style-name": "1-P1", + }, + }, + "draw:text-style-name": "1-P1", + "presentation:class": "title", + "presentation:style-name": "1-pr6", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "0.325cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "0.032cm", + "text:list": Object { + "text:list-item": Array [ + Object { + "text:p": Object { + "$t": "State the desired goal", + "text:style-name": "1-P5", + }, + }, + Object { + "text:p": Object { + "$t": "Define the goal in more detail", + "text:style-name": "1-P5", + }, + }, + ], + "text:style-name": "1-L3", + }, + }, + "draw:text-style-name": "1-P6", + "presentation:class": "outline", + "presentation:style-name": "1-pr5", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.548cm", + "svg:x": "3.023cm", + "svg:y": "6.178cm", + }, + ], + "draw:master-page-name": "prs-strategy", + "draw:name": "Long-term goal", + "draw:style-name": "1-dp3", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "1-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "1-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "3", + "draw:style-name": "1-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "1-dp2", + }, + "presentation:presentation-page-layout-name": "A1-L21-T1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "9.472cm", + "text:p": Object { + "$t": "The Present Situation", + "text:style-name": "1-P1", + }, + }, + "draw:text-style-name": "1-P1", + "presentation:class": "title", + "presentation:style-name": "1-pr7", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "0.325cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "9.472cm", + "text:list": Object { + "text:list-item": Object { + "text:p": Object { + "$t": "Give a summary of the current situation", + "text:style-name": "1-P5", + }, + }, + "text:style-name": "1-L3", + }, + }, + "draw:text-style-name": "1-P6", + "presentation:class": "outline", + "presentation:style-name": "1-pr5", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.548cm", + "svg:x": "3.023cm", + "svg:y": "6.178cm", + }, + ], + "draw:master-page-name": "prs-strategy", + "draw:name": "The Present Situation", + "draw:style-name": "1-dp3", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "1-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "1-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "4", + "draw:style-name": "1-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "1-dp2", + }, + "presentation:presentation-page-layout-name": "A1-L21-T1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "10.162cm", + "text:p": Object { + "$t": "Development up to present", + "text:style-name": "1-P1", + }, + }, + "draw:text-style-name": "1-P1", + "presentation:class": "title", + "presentation:style-name": "1-pr8", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "0.325cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "10.162cm", + "text:list": Object { + "text:list-item": Array [ + Object { + "text:p": Object { + "$t": "Development made up to the current situation", + "text:style-name": "1-P5", + }, + }, + Object { + "text:p": Object { + "$t": "Important background information", + "text:style-name": "1-P5", + }, + }, + Object { + "text:p": Object { + "$t": "Original forecasts which turned out to be wrong", + "text:style-name": "1-P5", + }, + }, + Object { + "text:p": Object { + "$t": "Original forecasts which turned out to be true", + "text:style-name": "1-P5", + }, + }, + ], + "text:style-name": "1-L3", + }, + }, + "draw:text-style-name": "1-P6", + "presentation:class": "outline", + "presentation:style-name": "1-pr5", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.548cm", + "svg:x": "3.023cm", + "svg:y": "6.178cm", + }, + ], + "draw:master-page-name": "prs-strategy", + "draw:name": "Development up to present", + "draw:style-name": "1-dp3", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "1-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "1-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "5", + "draw:style-name": "1-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "1-dp2", + }, + "presentation:presentation-page-layout-name": "A1-L21-T1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "0.024cm", + "text:p": Object { + "$t": "Potential Alternatives", + "text:style-name": "1-P1", + }, + }, + "draw:text-style-name": "1-P1", + "presentation:class": "title", + "presentation:style-name": "1-pr9", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "0.325cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "draw:corner-radius": "0.024cm", + "text:list": Object { + "text:list-item": Array [ + Object { + "text:p": Object { + "$t": "State the alternative strategies", + "text:style-name": "1-P5", + }, + }, + Object { + "text:p": Object { + "$t": "List the pros and cons of each strategy", + "text:style-name": "1-P5", + }, + }, + Object { + "text:p": Object { + "$t": "Give a forecast of costs", + "text:style-name": "1-P5", + }, + }, + ], + "text:style-name": "1-L3", + }, + }, + "draw:text-style-name": "1-P6", + "presentation:class": "outline", + "presentation:style-name": "1-pr5", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.548cm", + "svg:x": "3.023cm", + "svg:y": "6.178cm", + }, + ], + "draw:master-page-name": "prs-strategy", + "draw:name": "Potential Alternatives", + "draw:style-name": "1-dp3", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "1-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "1-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "6", + "draw:style-name": "1-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "1-dp2", + }, + "presentation:presentation-page-layout-name": "A1-L21-T1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "text:p": Object { + "$t": "Recommendation", + "text:style-name": "1-P1", + }, + }, + "draw:text-style-name": "1-P1", + "presentation:class": "title", + "presentation:style-name": "1-1-pr10", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "0.325cm", + }, + Object { + "draw:layer": "layout", + "draw:text-box": Object { + "text:list": Object { + "text:list-item": Array [ + Object { + "text:p": Object { + "$t": "Recommend one or several strategies", + "text:style-name": "1-P5", + }, + }, + Object { + "text:p": Object { + "$t": "Give a summary of the expected results", + "text:style-name": "1-P5", + }, + }, + Object { + "text:p": Object { + "$t": "Name the next steps to be taken", + "text:style-name": "1-P5", + }, + }, + Object { + "text:p": Object { + "$t": "Delegate the various tasks", + "text:style-name": "1-P5", + }, + }, + ], + "text:style-name": "1-L3", + }, + }, + "draw:text-style-name": "1-P6", + "presentation:class": "outline", + "presentation:style-name": "1-pr5", + "presentation:user-transformed": "true", + "svg:height": "13.231cm", + "svg:width": "23.548cm", + "svg:x": "3.023cm", + "svg:y": "6.178cm", + }, + ], + "draw:master-page-name": "prs-strategy", + "draw:name": "Recommendation", + "draw:style-name": "1-dp3", + "office:forms": Object { + "form:apply-design-mode": "false", + "form:automatic-focus": "false", + }, + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "layout", + "draw:text-box": Object {}, + "draw:text-style-name": "1-P4", + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "1-pr3", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "layout", + "draw:page-number": "7", + "draw:style-name": "1-gr1", + "presentation:class": "page", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "draw:style-name": "1-dp2", + }, + "presentation:presentation-page-layout-name": "A1-L21-T1", + }, + ], + "presentation:settings": Array [ + Object { + "presentation:mouse-visible": "false", + "presentation:stay-on-top": "true", + }, + Object { + "presentation:mouse-visible": "false", + "presentation:stay-on-top": "true", + }, + ], + }, + }, + "xmlns:anim": "urn:oasis:names:tc:opendocument:xmlns:animation:1.0", + "xmlns:chart": "urn:oasis:names:tc:opendocument:xmlns:chart:1.0", + "xmlns:dc": "http://purl.org/dc/elements/1.1/", + "xmlns:dom": "http://www.w3.org/2001/xml-events", + "xmlns:dr3d": "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0", + "xmlns:draw": "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", + "xmlns:drawooo": "http://openoffice.org/2010/draw", + "xmlns:field": "urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0", + "xmlns:fo": "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0", + "xmlns:form": "urn:oasis:names:tc:opendocument:xmlns:form:1.0", + "xmlns:grddl": "http://www.w3.org/2003/g/data-view#", + "xmlns:math": "http://www.w3.org/1998/Math/MathML", + "xmlns:meta": "urn:oasis:names:tc:opendocument:xmlns:meta:1.0", + "xmlns:number": "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0", + "xmlns:of": "urn:oasis:names:tc:opendocument:xmlns:of:1.2", + "xmlns:office": "urn:oasis:names:tc:opendocument:xmlns:office:1.0", + "xmlns:officeooo": "http://openoffice.org/2009/office", + "xmlns:ooo": "http://openoffice.org/2004/office", + "xmlns:oooc": "http://openoffice.org/2004/calc", + "xmlns:ooow": "http://openoffice.org/2004/writer", + "xmlns:presentation": "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0", + "xmlns:rpt": "http://openoffice.org/2005/report", + "xmlns:script": "urn:oasis:names:tc:opendocument:xmlns:script:1.0", + "xmlns:smil": "urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0", + "xmlns:style": "urn:oasis:names:tc:opendocument:xmlns:style:1.0", + "xmlns:svg": "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0", + "xmlns:table": "urn:oasis:names:tc:opendocument:xmlns:table:1.0", + "xmlns:tableooo": "http://openoffice.org/2009/table", + "xmlns:text": "urn:oasis:names:tc:opendocument:xmlns:text:1.0", + "xmlns:xforms": "http://www.w3.org/2002/xforms", + "xmlns:xhtml": "http://www.w3.org/1999/xhtml", + "xmlns:xlink": "http://www.w3.org/1999/xlink", + "xmlns:xsd": "http://www.w3.org/2001/XMLSchema", + "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", + }, +} +`; + exports[`Document manifest returns the correct formatting for mimetype 1`] = ` Object { "manifest:manifest": Object { diff --git a/__tests__/__snapshots__/Slide.test.js.snap b/__tests__/__snapshots__/Slide.test.js.snap deleted file mode 100644 index fc0d49c..0000000 --- a/__tests__/__snapshots__/Slide.test.js.snap +++ /dev/null @@ -1,23 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Slide .styleIDs returns the ids for the slide 1`] = ` -Array [ - "dp1", -] -`; - -exports[`Slide .styles includes the styles for the given slide 1`] = ` -Array [ - Object { - "style:drawing-page-properties": Object { - "presentation:background-objects-visible": "true", - "presentation:background-visible": "true", - "presentation:display-date-time": "true", - "presentation:display-footer": "true", - "presentation:display-page-number": "false", - }, - "style:family": "drawing-page", - "style:name": "dp1", - }, -] -`; diff --git a/src/Document.js b/src/Document.js index b2c953c..80754ea 100644 --- a/src/Document.js +++ b/src/Document.js @@ -49,46 +49,41 @@ export default class Document extends EventEmitter { const content = files.find(f => f.path === 'content.xml'); const stylesDocument = files.find(f => f.path === 'styles.xml'); let manifest = this.mergeManifest(files); - let pres = new Presentation(JSON.parse(toJson(content.data))); + let pres = new Presentation(JSON.parse(toJson(content.data)), this.counter); let style = new Style( JSON.parse(toJson(stylesDocument.data)), pres, manifest ); - this.merge(pres, manifest); + this.mergeContent(pres, manifest); this.mergeStyles(style, manifest); this.counter = this.counter + 1; } - merge(pres) { - if (!(pres instanceof Presentation)) { - throw new TypeError( - `expected Presentation class got ${pres.constructor.name}` - ); - } - this.slides = this.slides.concat(pres.slides); - let slides = this.slides.map(slidesDocument => slidesDocument.content); - let styles = this.slides - .map(slidesDocument => slidesDocument.styles) - .flat(); + get contentKeys () { + return [ + "office:document-content.office:automatic-styles.style:style", + "office:document-content.office:automatic-styles.text:list-style", + "office:document-content.office:body.office:presentation.draw:page", + "office:document-content.office:body.office:presentation.presentation:settings" + ] + } - Object.assign(this.doc['office:document-content'], pres.namespaces); - set( - this.doc, - [ - 'office:document-content', - 'office:body', - 'office:presentation', - 'draw:page', - ], - slides - ); + mergeContent(pres) { + for(let [key,value] of Object.entries(pres.namespaces)) { + this.doc['office:document-content'][key] = value; + } + this.contentKeys.forEach(key => { + this._content(pres, key) + }) + } - set( - this.doc, - ['office:document-content', 'office:automatic-styles', 'style:style'], - styles - ); + _content(object, key) { + if (!this[key]) { + this[key] = new Set(); + } + extractArray(object.data, key).forEach(i => this[key].add(i)); + set(this.doc, key, Array.from(this[key])); } pipe(stream) { diff --git a/src/Presentation.js b/src/Presentation.js index 9b79132..ab66897 100644 --- a/src/Presentation.js +++ b/src/Presentation.js @@ -1,20 +1,41 @@ -import { get } from "shvl"; -import { namespaces } from './utils' -import Slide from "./Slide"; +import { get } from 'shvl'; +import { namespaces, uuid } from './utils'; export default class Presentation { - constructor(presentation) { - this.presentation = presentation; - this.namespaces = namespaces(presentation['office:document-content']) + constructor(presentation, id) { + this.id = id; + if (id === undefined) { + this.id = uuid(); + } + this.data = presentation; + this._uniqueStyleIDs(); + this.presentation = this.data; + this.namespaces = namespaces(presentation['office:document-content']); } - get slides() { - const slides = - get(this.presentation, [ - "office:document-content", - "office:body", - "office:presentation", - "draw:page" - ]) || []; - return slides.map(slide => new Slide(slide, this.presentation)); + _uniqueStyleIDs() { + [ + 'office:document-content.office:automatic-styles.style:style', + 'office:document-content.office:automatic-styles.text:list-style', + ].forEach(key => { + this.data = this._renameStyleKeys(this.data, key); + }); + } + + _renameStyleKeys(document, key) { + let styles = get(document, key); + let keys = new Set(); + styles.forEach(style => { + Object.entries(style).forEach(([key, value]) => { + if (key.endsWith(':name')) { + keys.add(value); + } + }); + }); + let str = JSON.stringify(document); + keys.forEach(key => { + let newId = `${this.id}-${key}`; + str = str.replace(new RegExp(key, 'g'), newId); + }); + return JSON.parse(str); } } diff --git a/src/Slide.js b/src/Slide.js deleted file mode 100644 index a1a9c43..0000000 --- a/src/Slide.js +++ /dev/null @@ -1,59 +0,0 @@ -import { moveImageReferences } from './utils' -import { get } from 'shvl'; - -/** - * A presentation slide representation - * @class - * @params {Object} content - The presentation slide content - * @params {Object} presentation - The entire presentation - */ -export default class Slide { - constructor(content, presentation, manifest) { - this.content = moveImageReferences(content, manifest); - this.presentation = presentation; - } - - /** - * @getter - * @description finds and returns the style name ids from within - * the slide content - * @returns {array} - array of style name IDs - */ - get styleIDs() { - let ids = []; - ids.push(this.content['draw:style-name']); - ['draw:frame', 'draw:custom-shape', 'draw:connector'].forEach(key => { - if (this.content[key]) { - if (Array.isArray(this.content[key])) { - this.content[key].forEach(item => { - if (item['draw:style-name']) { - ids.push(item['draw:style-name']); - } - }); - } else { - ids.push(this.content[key]['draw:style-name']); - } - } - }); - - return ids; - } - - /** - * @getter - * @description finds and returns all the styles associated to the slide - * from the global collection - * @returns {array} - array of objects from the styling - */ - get styles() { - const documentStyles = - get(this.presentation, [ - 'office:document-content', - 'office:automatic-styles', - 'style:style', - ]) || []; - return documentStyles.filter(item => { - return this.styleIDs.includes(item['style:name']); - }); - } -} diff --git a/src/utils.js b/src/utils.js index e22ee00..b638bc1 100644 --- a/src/utils.js +++ b/src/utils.js @@ -48,4 +48,11 @@ export function extractArray(input, key) { } else { return data; } +} + +export function uuid() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); } \ No newline at end of file From b3dbdb9dc513c927dd6792e98f965f130162806f Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Wed, 4 Mar 2020 16:10:23 +0000 Subject: [PATCH 07/13] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20DRY=20merge=20styles?= =?UTF-8?q?=20merge=20content?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Document.js | 77 +++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/src/Document.js b/src/Document.js index 80754ea..a2ea0cf 100644 --- a/src/Document.js +++ b/src/Document.js @@ -68,22 +68,51 @@ export default class Document extends EventEmitter { "office:document-content.office:body.office:presentation.presentation:settings" ] } + + get styleKeys () { + return [ + 'office:document-styles.office:styles.draw:gradient', + 'office:document-styles.office:styles.draw:hatch', + 'office:document-styles.office:styles.draw:fill-image', + 'office:document-styles.office:styles.draw:marker', + 'office:document-styles.office:styles.draw:stroke-dash', + 'office:document-styles.office:styles.style:default-style', + 'office:document-styles.office:styles.style:style', + /** + * @warning `presentation-page-layout` causes OpenOffice to crash when opening the document + */ + // 'office:document-styles.office:styles.style:presentation-page-layout', + 'office:document-styles.office:automatic-styles.style:page-layout', + 'office:document-styles.office:automatic-styles.style:style', + 'office:document-styles.office:master-styles.draw:layer-set', + 'office:document-styles.office:master-styles.style:handout-master', + 'office:document-styles.office:master-styles.style:master-page', + ] + } mergeContent(pres) { - for(let [key,value] of Object.entries(pres.namespaces)) { - this.doc['office:document-content'][key] = value; + this._merge(this.doc, pres, 'office:document-content', this.contentKeys) + } + + mergeStyles(style) { + this._merge(this.stylesDoc, style, 'office:document-styles', this.styleKeys) + } + + _merge(doc, obj, rootKey, keys) { + for(let [key,value] of Object.entries(obj.namespaces)) { + doc[rootKey][key] = value; } - this.contentKeys.forEach(key => { - this._content(pres, key) + keys.forEach(key => { + this._content(doc, obj.data, key) }) } - _content(object, key) { + _content(doc, data, key) { if (!this[key]) { this[key] = new Set(); } - extractArray(object.data, key).forEach(i => this[key].add(i)); - set(this.doc, key, Array.from(this[key])); + extractArray(data, key).forEach(i => this[key].add(i)); + set(doc, key, Array.from(this[key])); } pipe(stream) { @@ -157,40 +186,6 @@ export default class Document extends EventEmitter { } } - mergeStyles(style) { - for (let [key, value] of Object.entries(style.namespaces)) { - this.stylesDoc['office:document-styles'][key] = value; - } - [ - 'office:document-styles.office:styles.draw:gradient', - 'office:document-styles.office:styles.draw:hatch', - 'office:document-styles.office:styles.draw:fill-image', - 'office:document-styles.office:styles.draw:marker', - 'office:document-styles.office:styles.draw:stroke-dash', - 'office:document-styles.office:styles.style:default-style', - 'office:document-styles.office:styles.style:style', - /** - * @warning `presentation-page-layout` causes OpenOffice to crash when opening the document - */ - // 'office:document-styles.office:styles.style:presentation-page-layout', - 'office:document-styles.office:automatic-styles.style:page-layout', - 'office:document-styles.office:automatic-styles.style:style', - 'office:document-styles.office:master-styles.draw:layer-set', - 'office:document-styles.office:master-styles.style:handout-master', - 'office:document-styles.office:master-styles.style:master-page', - ].forEach(key => { - this._styleContent(style, key); - }); - } - - _styleContent(style, key) { - if (!this[key]) { - this[key] = new Set(); - } - extractArray(style.data, key).forEach(i => this[key].add(i)); - set(this.stylesDoc, key, Array.from(this[key])); - } - mergeManifest(files) { const manifest = files.find(f => f.path === 'META-INF/manifest.xml'); let json = JSON.parse(toJson(manifest.data)); From 0bd9c15824aba04521b1b3c8f412fffb9f161b39 Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Fri, 6 Mar 2020 11:21:31 +0000 Subject: [PATCH 08/13] =?UTF-8?q?=E2=9C=85=20code=20coverage=20for=20docum?= =?UTF-8?q?ent=20pipe=20failure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/Document.test.js | 29 ++++++++++++++++++++++++++++- src/Document.js | 20 ++++++++++++-------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/__tests__/Document.test.js b/__tests__/Document.test.js index 009b2f6..d50b3f8 100644 --- a/__tests__/Document.test.js +++ b/__tests__/Document.test.js @@ -115,7 +115,7 @@ describe('Document', () => { subject.mergeContent(new Presentation(fixture1, 0)); subject.mergeContent(new Presentation(fixture2, 1)); - expect(subject.doc).toMatchSnapshot() + expect(subject.doc).toMatchSnapshot(); }); }); @@ -171,4 +171,31 @@ describe('Document', () => { }); }); }); + + describe('pipe', () => { + let tmpfile = './tmpfile' + beforeEach(() => { + subject = new Document(); + }); + afterEach(() => { + fs.unlinkSync(tmpfile) + }) + + it('handles error', async () => { + expect.assertions(2); + let stream = fs.createWriteStream(tmpfile); + stream.destroy(); + subject.on('error', err => { + expect(err).toMatchInlineSnapshot( + `[Error: Cannot call write after a stream was destroyed]` + ); + }); + return subject.pipe(stream).catch(e => { + expect(e).toMatchInlineSnapshot( + Error, + `[Error: Cannot call write after a stream was destroyed]` + ); + }); + }); + }); }); diff --git a/src/Document.js b/src/Document.js index a2ea0cf..e6fa2fa 100644 --- a/src/Document.js +++ b/src/Document.js @@ -115,6 +115,17 @@ export default class Document extends EventEmitter { set(doc, key, Array.from(this[key])); } + get ZIPOptions() { + return { + type: 'nodebuffer', + streamFiles: true, + compression: 'DEFLATE', + compressionOptions: { + level: 9, + }, + }; + } + pipe(stream) { let zip = new JSZip(); this.files.forEach(file => { @@ -126,14 +137,7 @@ export default class Document extends EventEmitter { zip.file('META-INF/manifest.xml', this.toFormattedXML(this.manifest)); let promise = new Promise((resolve, reject) => { zip - .generateNodeStream({ - type: 'nodebuffer', - streamFiles: true, - compression: 'DEFLATE', - compressionOptions: { - level: 9, - }, - }) + .generateNodeStream(this.ZIPOptions) .pipe(stream) .on('finish', () => { resolve(); From e6eca4fa1bdd2342db7a9de9f0ad8e22baa00ded Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Fri, 6 Mar 2020 11:22:04 +0000 Subject: [PATCH 09/13] =?UTF-8?q?=E2=9C=85=20Simplify=20document=20master?= =?UTF-8?q?=20page=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/Document.test.js | 10 +- __tests__/__snapshots__/Document.test.js.snap | 145 ++++++++++++++++++ 2 files changed, 147 insertions(+), 8 deletions(-) diff --git a/__tests__/Document.test.js b/__tests__/Document.test.js index d50b3f8..aa3e06c 100644 --- a/__tests__/Document.test.js +++ b/__tests__/Document.test.js @@ -148,14 +148,8 @@ describe('Document', () => { actual = get(subject.stylesDoc, key); }); - it('contains the master style names', () => { - let actualNames = actual.map(i => i['style:name']); - expect(actualNames).toMatchSnapshot(); - }); - - it('contains the master frames', () => { - let actualNames = actual.map(i => i['draw:frame']); - expect(actualNames).toMatchSnapshot(); + it('contains the expected master pages', () => { + expect(actual).toMatchSnapshot(); }); }); diff --git a/__tests__/__snapshots__/Document.test.js.snap b/__tests__/__snapshots__/Document.test.js.snap index 199a908..2a8e0c4 100644 --- a/__tests__/__snapshots__/Document.test.js.snap +++ b/__tests__/__snapshots__/Document.test.js.snap @@ -2880,6 +2880,151 @@ Object { } `; +exports[`Document mergeStyles master-page contains the expected master pages 1`] = ` +Array [ + Object { + "draw:frame": Array [ + Object { + "draw:image": Object { + "text:p": Object {}, + "xlink:actuate": "onLoad", + "xlink:href": "Pictures/100000000000032000000258E080B12F.jpg", + "xlink:show": "embed", + "xlink:type": "simple", + }, + "draw:layer": "backgroundobjects", + "draw:style-name": "Mgr1", + "draw:text-style-name": "MP1", + "svg:height": "21cm", + "svg:width": "28cm", + "svg:x": "-0.001cm", + "svg:y": "-0.001cm", + }, + Object { + "draw:layer": "backgroundobjects", + "draw:text-box": Object {}, + "presentation:class": "title", + "presentation:placeholder": "true", + "presentation:style-name": "prs-novelty-title", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "1.943cm", + }, + Object { + "draw:layer": "backgroundobjects", + "draw:text-box": Object {}, + "presentation:class": "outline", + "presentation:placeholder": "true", + "presentation:style-name": "prs-novelty-outline1", + "svg:height": "13.23cm", + "svg:width": "23.384cm", + "svg:x": "2.285cm", + "svg:y": "5.938cm", + }, + ], + "draw:style-name": "Mdp1", + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "backgroundobjects", + "draw:text-box": Object { + "draw:corner-radius": "3107.312cm", + }, + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "prs-novelty-notes", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "backgroundobjects", + "presentation:class": "page", + "presentation:style-name": "prs-novelty-title", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "style:page-layout-name": "PM2", + }, + "style:name": "prs-novelty", + "style:page-layout-name": "PM1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "backgroundobjects", + "draw:text-box": Object { + "draw:corner-radius": "0.065cm", + }, + "presentation:class": "title", + "presentation:placeholder": "true", + "presentation:style-name": "prs-strategy-title", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "0.325cm", + }, + Object { + "draw:layer": "backgroundobjects", + "draw:text-box": Object {}, + "presentation:class": "outline", + "presentation:placeholder": "true", + "presentation:style-name": "prs-strategy-outline1", + "svg:height": "13.23cm", + "svg:width": "23.548cm", + "svg:x": "3.023cm", + "svg:y": "6.178cm", + }, + Object { + "draw:image": Object { + "text:p": Object {}, + "xlink:actuate": "onLoad", + "xlink:href": "Pictures/2000023600002305000012CD3628FC8C.wmf", + "xlink:show": "embed", + "xlink:type": "simple", + }, + "draw:layer": "backgroundobjects", + "draw:style-name": "Mgr1", + "draw:text-style-name": "MP1", + "svg:height": "2.937cm", + "svg:width": "5.47cm", + "svg:x": "22.048cm", + "svg:y": "17.365cm", + }, + ], + "draw:style-name": "Mdp1", + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "backgroundobjects", + "draw:text-box": Object {}, + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "prs-strategy-notes", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "backgroundobjects", + "presentation:class": "page", + "presentation:style-name": "prs-strategy-title", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "style:page-layout-name": "PM2", + }, + "style:name": "prs-strategy", + "style:page-layout-name": "PM1", + }, +] +`; + exports[`Document mergeStyles master-page contains the master frames 1`] = ` Array [ Array [ From d664faf77443a1b78033550d330b3a8f29e1a1e7 Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Fri, 6 Mar 2020 11:32:02 +0000 Subject: [PATCH 10/13] =?UTF-8?q?=F0=9F=9A=A8=20enhanced=20linting=20with?= =?UTF-8?q?=20prettier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintignore | 3 + .eslintrc.js | 4 +- __tests__/.eslintrc.json | 5 +- __tests__/Document.test.js | 6 +- __tests__/Presentation.test.js | 16 +++-- __tests__/Style.test.js | 6 +- babel.config.js | 12 ++-- bin/presentation-merger.js | 2 +- index.js | 2 +- src/Document.js | 127 +++++++++++++++++---------------- src/index.js | 19 +++-- src/utils.js | 23 +++--- 12 files changed, 126 insertions(+), 99 deletions(-) create mode 100644 .eslintignore diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..9e54f1f --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +lib +node_modules +coverage \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 25bb574..786f60c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -7,7 +7,9 @@ module.exports = { parser: 'babel-eslint', extends: ['eslint:recommended', 'plugin:prettier/recommended'], rules: { - 'prettier/prettier': 'off', + 'semi': ['error', 'always'], + 'prettier/prettier': 'error', + 'max-lines-per-function': ['error', 25], 'no-console': [ 'error', { diff --git a/__tests__/.eslintrc.json b/__tests__/.eslintrc.json index 4e65448..c236e97 100644 --- a/__tests__/.eslintrc.json +++ b/__tests__/.eslintrc.json @@ -7,5 +7,8 @@ ], "extends": [ "plugin:jest/recommended" - ] + ], + "rules": { + "max-lines-per-function": "off" + } } \ No newline at end of file diff --git a/__tests__/Document.test.js b/__tests__/Document.test.js index aa3e06c..8f1738d 100644 --- a/__tests__/Document.test.js +++ b/__tests__/Document.test.js @@ -167,13 +167,13 @@ describe('Document', () => { }); describe('pipe', () => { - let tmpfile = './tmpfile' + let tmpfile = './tmpfile'; beforeEach(() => { subject = new Document(); }); afterEach(() => { - fs.unlinkSync(tmpfile) - }) + fs.unlinkSync(tmpfile); + }); it('handles error', async () => { expect.assertions(2); diff --git a/__tests__/Presentation.test.js b/__tests__/Presentation.test.js index b347e95..49a6239 100644 --- a/__tests__/Presentation.test.js +++ b/__tests__/Presentation.test.js @@ -3,14 +3,16 @@ import path from 'path'; import Presenation from '../src/Presentation'; const fixture = JSON.parse( - fs.readFileSync(path.join(__dirname, "__fixtures__/example.json")) + fs.readFileSync(path.join(__dirname, '__fixtures__/example.json')) ); -describe("Presentation", () => { +describe('Presentation', () => { describe('.uniqueStyleIDs()', () => { it('renames style names with a prefixed ID', () => { - let subject = new Presenation(fixture, 0) - expect(JSON.stringify(subject.data)).toContain('"text:style-name":"0-a1219"') - }) - }) -}) \ No newline at end of file + let subject = new Presenation(fixture, 0); + expect(JSON.stringify(subject.data)).toContain( + '"text:style-name":"0-a1219"' + ); + }); + }); +}); diff --git a/__tests__/Style.test.js b/__tests__/Style.test.js index 9423f7a..9c0dbc1 100644 --- a/__tests__/Style.test.js +++ b/__tests__/Style.test.js @@ -10,14 +10,12 @@ describe('Style', () => { path.join(__dirname, '__fixtures__/file1.odp') ); const masterStylesFile = files.find(f => f.path === 'styles.xml'); - subject = new Style( - JSON.parse(toJson(masterStylesFile.data)) - ); + subject = new Style(JSON.parse(toJson(masterStylesFile.data))); }); describe('namespaces', () => { it('returns the style XML namespaces for this presentation', () => { - expect(subject.namespaces).toMatchSnapshot() + expect(subject.namespaces).toMatchSnapshot(); }); }); }); diff --git a/babel.config.js b/babel.config.js index 223b8fe..f037a1a 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,12 +1,12 @@ module.exports = { presets: [ [ - "@babel/preset-env", + '@babel/preset-env', { targets: { - node: "current" - } - } - ] - ] + node: 'current', + }, + }, + ], + ], }; diff --git a/bin/presentation-merger.js b/bin/presentation-merger.js index 8381af5..f50c374 100755 --- a/bin/presentation-merger.js +++ b/bin/presentation-merger.js @@ -5,7 +5,7 @@ const chalk = require('chalk'); const fs = require('fs'); const path = require('path'); const packageJson = require('../package.json'); -const debug = require('debug')('presentation-merger') +const debug = require('debug')('presentation-merger'); const mergeFiles = require('../lib/index.js').default; debug(`Dependencies loaded ${process.hrtime(bootStart)[1] / 1000000}ms`); diff --git a/index.js b/index.js index 211e452..3fc7798 100644 --- a/index.js +++ b/index.js @@ -1 +1 @@ -module.exports = require('./src'); \ No newline at end of file +module.exports = require('./src'); diff --git a/src/Document.js b/src/Document.js index e6fa2fa..270260f 100644 --- a/src/Document.js +++ b/src/Document.js @@ -4,7 +4,7 @@ import decompress from 'decompress'; import EventEmitter from 'events'; import { toJson, toXml } from 'xml2json'; import { format } from 'prettier'; -import { extractArray } from './utils' +import { extractArray } from './utils'; import Presentation from './Presentation'; import Style from './Style'; @@ -41,7 +41,7 @@ export default class Document extends EventEmitter { mimeType: 'text/xml', path: 'styles.xml', }, - ] + ]; } async mergeFile(file) { @@ -60,16 +60,16 @@ export default class Document extends EventEmitter { this.counter = this.counter + 1; } - get contentKeys () { + get contentKeys() { return [ - "office:document-content.office:automatic-styles.style:style", - "office:document-content.office:automatic-styles.text:list-style", - "office:document-content.office:body.office:presentation.draw:page", - "office:document-content.office:body.office:presentation.presentation:settings" - ] - } - - get styleKeys () { + 'office:document-content.office:automatic-styles.style:style', + 'office:document-content.office:automatic-styles.text:list-style', + 'office:document-content.office:body.office:presentation.draw:page', + 'office:document-content.office:body.office:presentation.presentation:settings', + ]; + } + + get styleKeys() { return [ 'office:document-styles.office:styles.draw:gradient', 'office:document-styles.office:styles.draw:hatch', @@ -87,24 +87,29 @@ export default class Document extends EventEmitter { 'office:document-styles.office:master-styles.draw:layer-set', 'office:document-styles.office:master-styles.style:handout-master', 'office:document-styles.office:master-styles.style:master-page', - ] + ]; } mergeContent(pres) { - this._merge(this.doc, pres, 'office:document-content', this.contentKeys) + this._merge(this.doc, pres, 'office:document-content', this.contentKeys); } mergeStyles(style) { - this._merge(this.stylesDoc, style, 'office:document-styles', this.styleKeys) + this._merge( + this.stylesDoc, + style, + 'office:document-styles', + this.styleKeys + ); } _merge(doc, obj, rootKey, keys) { - for(let [key,value] of Object.entries(obj.namespaces)) { + for (let [key, value] of Object.entries(obj.namespaces)) { doc[rootKey][key] = value; } keys.forEach(key => { - this._content(doc, obj.data, key) - }) + this._content(doc, obj.data, key); + }); } _content(doc, data, key) { @@ -127,16 +132,8 @@ export default class Document extends EventEmitter { } pipe(stream) { - let zip = new JSZip(); - this.files.forEach(file => { - zip.file(file.path, file.data); - }); - zip.file('mimetype', 'application/vnd.oasis.opendocument.presentation'); - zip.file('content.xml', this.toFormattedXML(this.doc)); - zip.file('styles.xml', this.toFormattedXML(this.stylesDoc)); - zip.file('META-INF/manifest.xml', this.toFormattedXML(this.manifest)); let promise = new Promise((resolve, reject) => { - zip + this._zipFiles() .generateNodeStream(this.ZIPOptions) .pipe(stream) .on('finish', () => { @@ -151,6 +148,18 @@ export default class Document extends EventEmitter { return promise; } + _zipFiles() { + let zip = new JSZip(); + this.files.forEach(file => { + zip.file(file.path, file.data); + }); + zip.file('mimetype', 'application/vnd.oasis.opendocument.presentation'); + zip.file('content.xml', this.toFormattedXML(this.doc)); + zip.file('styles.xml', this.toFormattedXML(this.stylesDoc)); + zip.file('META-INF/manifest.xml', this.toFormattedXML(this.manifest)); + return zip; + } + get manifest() { let output = { 'manifest:manifest': { @@ -175,19 +184,11 @@ export default class Document extends EventEmitter { } toFormattedXML(object) { - try { - return format( - toXml(object), - { - xmlSelfClosingSpace: true, - xmlWhitespaceSensitivity: 'ignore', - parser: 'xml', - } - ); - } catch (err) { - console.error(err); - return toXml(object); - } + return format(toXml(object), { + xmlSelfClosingSpace: true, + xmlWhitespaceSensitivity: 'ignore', + parser: 'xml', + }); } mergeManifest(files) { @@ -195,27 +196,33 @@ export default class Document extends EventEmitter { let json = JSON.parse(toJson(manifest.data)); const manifestFiles = get(json, 'manifest:manifest.manifest:file-entry'); return manifestFiles - .map(manifestFile => { - if ( - manifestFile['manifest:media-type'].startsWith('image/') || - manifestFile['manifest:full-path'].endsWith('.wmf') - ) { - const file = files.find( - f => f.path === manifestFile['manifest:full-path'] - ); - file.path = `Presentation${this.counter}-${file.path}`; - this.files.push(file); - this.manifestFiles.push({ - mimeType: manifestFile['manifest:media-type'], - path: file.path, - }); - return { - mimeType: manifestFile['manifest:media-type'], - pathPrevious: manifestFile['manifest:full-path'], - path: file.path, - }; - } - }) + .map(manifestFile => this._manifestMapEntry(files, manifestFile)) .filter(Boolean); } + + _manifestMapEntry(files, manifestFile) { + if (this._manifestIsImageEntry(manifestFile)) { + const file = files.find( + f => f.path === manifestFile['manifest:full-path'] + ); + file.path = `Presentation${this.counter}-${file.path}`; + this.files.push(file); + this.manifestFiles.push({ + mimeType: manifestFile['manifest:media-type'], + path: file.path, + }); + return { + mimeType: manifestFile['manifest:media-type'], + pathPrevious: manifestFile['manifest:full-path'], + path: file.path, + }; + } + } + + _manifestIsImageEntry(manifestFile) { + return ( + manifestFile['manifest:media-type'].startsWith('image/') || + manifestFile['manifest:full-path'].endsWith('.wmf') + ); + } } diff --git a/src/index.js b/src/index.js index e5b18c0..82dd846 100644 --- a/src/index.js +++ b/src/index.js @@ -1,12 +1,19 @@ import Document from './Document'; + +/** + * Merge files into a single document + * + * @param {stream.Writeable} stream Write stream to pipe the output to + * @param {array} files All the files to merge into a single document + */ export default async function mergeFile(stream, files) { const doc = new Document(); - for(let file of files) { - await doc.mergeFile(file) + for (let file of files) { + await doc.mergeFile(file); } - doc.pipe(stream) + doc.pipe(stream); return new Promise((resolve, reject) => { - doc.on('end', resolve) - doc.on('error', reject) - }) + doc.on('end', resolve); + doc.on('error', reject); + }); } diff --git a/src/utils.js b/src/utils.js index b638bc1..2f4726a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -2,13 +2,13 @@ import { get } from 'shvl'; /** * Replace images in content with references in the manifest from previous path locations - * + * * @param {object} data The content which needs any image references replacing * @param {array} manifest Manifest of files that are included in the document, with previous paths for lookup and replacement - * + * * @returns {object} Modified input data with any reference replaced within. */ -export function moveImageReferences(data, manifest=[]) { +export function moveImageReferences(data, manifest = []) { let str = JSON.stringify(data); manifest.forEach(i => { str = str.replace(new RegExp(i.pathPrevious, 'gi'), i.path); @@ -19,10 +19,10 @@ export function moveImageReferences(data, manifest=[]) { /** * Extract XML namespaces from the JSON representation of XML - * + * * @param {object} data The JSON representation of XML - * - * @returns {object} XML namespace keys pairs + * + * @returns {object} XML namespace keys pairs */ export function namespaces(data) { let out = {}; @@ -36,7 +36,7 @@ export function namespaces(data) { /** * Find, extract and return an array for the given dotnotation object key. - * + * * @param {object} input The object JSON representation of XML * @param {string} key The key to find in the object * @returns {array} Extracted array of content from the XML @@ -50,9 +50,14 @@ export function extractArray(input, key) { } } +/** + * Generates a UUID v4 + * @returns {string} generated UUID V4 + */ export function uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); + var r = (Math.random() * 16) | 0, + v = c == 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); -} \ No newline at end of file +} From c01bdead80f2e5482f5d41cc2b4b6b76d05e783e Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Fri, 6 Mar 2020 12:13:53 +0000 Subject: [PATCH 11/13] =?UTF-8?q?=F0=9F=93=9D=20Simple=20documentation=20f?= =?UTF-8?q?or=20core=20document=20classes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintignore | 4 +- .gitignore | 3 +- __tests__/Document.test.js | 5 +- __tests__/__snapshots__/Document.test.js.snap | 94 ------------ package-lock.json | 142 ++++++++++++++++-- package.json | 2 + src/Document.js | 20 ++- src/Presentation.js | 10 ++ src/Style.js | 11 +- 9 files changed, 173 insertions(+), 118 deletions(-) diff --git a/.eslintignore b/.eslintignore index 9e54f1f..94046c7 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,5 @@ lib node_modules -coverage \ No newline at end of file +coverage +out +docs \ No newline at end of file diff --git a/.gitignore b/.gitignore index e0c1948..4a04714 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ coverage *DS_Store __tests__/__fixtures__/output.odp lib -*.tgz \ No newline at end of file +*.tgz +docs \ No newline at end of file diff --git a/__tests__/Document.test.js b/__tests__/Document.test.js index 8f1738d..95da4a1 100644 --- a/__tests__/Document.test.js +++ b/__tests__/Document.test.js @@ -22,10 +22,7 @@ async function readFixture(filename) { const masterStylesFile = files.find(f => f.path === 'styles.xml'); const contentFile = files.find(f => f.path === 'content.xml'); const presentation = new Presentation(JSON.parse(toJson(contentFile.data))); - const style = new Style( - JSON.parse(toJson(masterStylesFile.data)), - presentation - ); + const style = new Style(JSON.parse(toJson(masterStylesFile.data))); const subject = new Document(); return { presentation, diff --git a/__tests__/__snapshots__/Document.test.js.snap b/__tests__/__snapshots__/Document.test.js.snap index 2a8e0c4..0389e70 100644 --- a/__tests__/__snapshots__/Document.test.js.snap +++ b/__tests__/__snapshots__/Document.test.js.snap @@ -3025,100 +3025,6 @@ Array [ ] `; -exports[`Document mergeStyles master-page contains the master frames 1`] = ` -Array [ - Array [ - Object { - "draw:image": Object { - "text:p": Object {}, - "xlink:actuate": "onLoad", - "xlink:href": "Pictures/100000000000032000000258E080B12F.jpg", - "xlink:show": "embed", - "xlink:type": "simple", - }, - "draw:layer": "backgroundobjects", - "draw:style-name": "Mgr1", - "draw:text-style-name": "MP1", - "svg:height": "21cm", - "svg:width": "28cm", - "svg:x": "-0.001cm", - "svg:y": "-0.001cm", - }, - Object { - "draw:layer": "backgroundobjects", - "draw:text-box": Object {}, - "presentation:class": "title", - "presentation:placeholder": "true", - "presentation:style-name": "prs-novelty-title", - "svg:height": "3.506cm", - "svg:width": "23.911cm", - "svg:x": "2.058cm", - "svg:y": "1.943cm", - }, - Object { - "draw:layer": "backgroundobjects", - "draw:text-box": Object {}, - "presentation:class": "outline", - "presentation:placeholder": "true", - "presentation:style-name": "prs-novelty-outline1", - "svg:height": "13.23cm", - "svg:width": "23.384cm", - "svg:x": "2.285cm", - "svg:y": "5.938cm", - }, - ], - Array [ - Object { - "draw:layer": "backgroundobjects", - "draw:text-box": Object { - "draw:corner-radius": "0.065cm", - }, - "presentation:class": "title", - "presentation:placeholder": "true", - "presentation:style-name": "prs-strategy-title", - "svg:height": "3.506cm", - "svg:width": "23.911cm", - "svg:x": "2.058cm", - "svg:y": "0.325cm", - }, - Object { - "draw:layer": "backgroundobjects", - "draw:text-box": Object {}, - "presentation:class": "outline", - "presentation:placeholder": "true", - "presentation:style-name": "prs-strategy-outline1", - "svg:height": "13.23cm", - "svg:width": "23.548cm", - "svg:x": "3.023cm", - "svg:y": "6.178cm", - }, - Object { - "draw:image": Object { - "text:p": Object {}, - "xlink:actuate": "onLoad", - "xlink:href": "Pictures/2000023600002305000012CD3628FC8C.wmf", - "xlink:show": "embed", - "xlink:type": "simple", - }, - "draw:layer": "backgroundobjects", - "draw:style-name": "Mgr1", - "draw:text-style-name": "MP1", - "svg:height": "2.937cm", - "svg:width": "5.47cm", - "svg:x": "22.048cm", - "svg:y": "17.365cm", - }, - ], -] -`; - -exports[`Document mergeStyles master-page contains the master style names 1`] = ` -Array [ - "prs-novelty", - "prs-strategy", -] -`; - exports[`Document mergeStyles merges style content from the presentation into the document style 1`] = ` Object { "office:document-styles": Object { diff --git a/package-lock.json b/package-lock.json index d461d48..daadef7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -313,8 +313,7 @@ "@babel/parser": { "version": "7.7.7", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", - "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", - "dev": true + "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==" }, "@babel/plugin-proposal-async-generator-functions": { "version": "7.7.4", @@ -1454,7 +1453,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -1749,6 +1747,11 @@ "safe-buffer": "^5.1.1" } }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1946,6 +1949,14 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, + "catharsis": { + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz", + "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==", + "requires": { + "lodash": "^4.17.14" + } + }, "chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -2664,6 +2675,11 @@ "once": "^1.4.0" } }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -5648,12 +5664,48 @@ } } }, + "js2xmlparser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz", + "integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==", + "requires": { + "xmlcreate": "^2.0.3" + } + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, + "jsdoc": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.3.tgz", + "integrity": "sha512-Yf1ZKA3r9nvtMWHO1kEuMZTlHOF8uoQ0vyo5eH7SQy5YeIiHM+B0DgKnn+X6y6KDYZcF7G2SPkKF+JORCXWE/A==", + "requires": { + "@babel/parser": "^7.4.4", + "bluebird": "^3.5.4", + "catharsis": "^0.8.11", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.0", + "klaw": "^3.0.0", + "markdown-it": "^8.4.2", + "markdown-it-anchor": "^5.0.2", + "marked": "^0.7.0", + "mkdirp": "^0.5.1", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.0.1", + "taffydb": "2.6.2", + "underscore": "~1.9.1" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + } + } + }, "jsdom": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", @@ -5762,6 +5814,14 @@ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true }, + "klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "requires": { + "graceful-fs": "^4.1.9" + } + }, "kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -5804,6 +5864,14 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", "dev": true }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "requires": { + "uc.micro": "^1.0.1" + } + }, "lint-staged": { "version": "9.5.0", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.5.0.tgz", @@ -6207,8 +6275,7 @@ "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, "lodash.sortby": { "version": "4.7.0", @@ -6386,6 +6453,33 @@ "object-visit": "^1.0.0" } }, + "markdown-it": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "requires": { + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + }, + "markdown-it-anchor": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.2.5.tgz", + "integrity": "sha512-xLIjLQmtym3QpoY9llBgApknl7pxAcN3WDRc2d3rwpl+/YvDZHPmKscGs+L6E05xf2KrCXPBvosWt7MZukwSpQ==" + }, + "marked": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", + "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==" + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -6480,7 +6574,6 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" }, @@ -6488,8 +6581,7 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" } } }, @@ -7325,6 +7417,14 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "requizzle": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", + "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", + "requires": { + "lodash": "^4.17.14" + } + }, "resolve": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz", @@ -7793,8 +7893,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { "version": "1.16.1", @@ -7967,8 +8066,7 @@ "strip-json-comments": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", - "dev": true + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==" }, "supports-color": { "version": "7.1.0", @@ -8009,6 +8107,11 @@ "string-width": "^3.0.0" } }, + "taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=" + }, "tar-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", @@ -8199,6 +8302,11 @@ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, "uglify-js": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.2.tgz", @@ -8235,6 +8343,11 @@ "through": "^2.3.8" } }, + "underscore": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.2.tgz", + "integrity": "sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ==" + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -8529,6 +8642,11 @@ "node-expat": "^2.3.18" } }, + "xmlcreate": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz", + "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index fd2b1bf..4060527 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "test": "jest", "lint": "eslint .", "lint:fix": "eslint --fix .", + "docs": "jsdoc src --destination docs", "build": "BABEL_ENV=production babel src --out-dir lib", "prepublish": "npm run lint && npm run test && npm run build" }, @@ -63,6 +64,7 @@ "commander": "^4.1.1", "debug": "^4.1.1", "decompress": "^4.2.0", + "jsdoc": "^3.6.3", "jszip": "^3.2.2", "prettier": "^1.19.1", "shvl": "^2.0.0", diff --git a/src/Document.js b/src/Document.js index 270260f..92bd64d 100644 --- a/src/Document.js +++ b/src/Document.js @@ -1,3 +1,4 @@ +/** @module Document */ import { get, set } from 'shvl'; import JSZip from 'jszip'; import decompress from 'decompress'; @@ -9,6 +10,10 @@ import { extractArray } from './utils'; import Presentation from './Presentation'; import Style from './Style'; +/** + * Class representing a new presentation document to merge files into + * @extends EventEmitter + */ export default class Document extends EventEmitter { constructor() { super({ captureRejections: true }); @@ -44,17 +49,17 @@ export default class Document extends EventEmitter { ]; } + /** + * Merge the given file to the document + * @param {string} file The file path to merge to the document + */ async mergeFile(file) { const files = await decompress(file); const content = files.find(f => f.path === 'content.xml'); const stylesDocument = files.find(f => f.path === 'styles.xml'); let manifest = this.mergeManifest(files); let pres = new Presentation(JSON.parse(toJson(content.data)), this.counter); - let style = new Style( - JSON.parse(toJson(stylesDocument.data)), - pres, - manifest - ); + let style = new Style(JSON.parse(toJson(stylesDocument.data)), manifest); this.mergeContent(pres, manifest); this.mergeStyles(style, manifest); this.counter = this.counter + 1; @@ -131,6 +136,11 @@ export default class Document extends EventEmitter { }; } + /** + * Pipe the merged files through the ZIP stream to return the expected encapulation for presentaitons. + * + * @param {stream.WriteStream} stream The output stream for the zipped contents to write to + */ pipe(stream) { let promise = new Promise((resolve, reject) => { this._zipFiles() diff --git a/src/Presentation.js b/src/Presentation.js index ab66897..1a08ef4 100644 --- a/src/Presentation.js +++ b/src/Presentation.js @@ -1,6 +1,16 @@ +/** @module Presentation */ import { get } from 'shvl'; import { namespaces, uuid } from './utils'; + +/** + * Class prepresenting `content.xml` in the presentation document + */ export default class Presentation { + /** + * Create a presentation content representation. + * @param {object} presentation JSON representation of content.xml + * @param {string} id unique identifier for the presentation + */ constructor(presentation, id) { this.id = id; if (id === undefined) { diff --git a/src/Style.js b/src/Style.js index b13a840..d642042 100644 --- a/src/Style.js +++ b/src/Style.js @@ -1,7 +1,16 @@ +/** @module Style */ import { moveImageReferences, namespaces } from './utils'; +/** + * Class prepresenting `style.xml` in the presentation document + */ export default class Style { - constructor(content, _, manifest) { + /** + * Create a style representation + * @param {object} content JSON representation of `style.xml` document + * @param {array} manifest The document manifest of image assets + */ + constructor(content, manifest) { this.data = moveImageReferences(content, manifest); this.namespaces = namespaces(content['office:document-styles']); } From 91a6f64e353d632ca487ab48d98f79bf35e1ae79 Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Fri, 6 Mar 2020 12:47:14 +0000 Subject: [PATCH 12/13] =?UTF-8?q?=F0=9F=9A=A8=20remove=20trailing=20comma?= =?UTF-8?q?=20linter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .codeclimate.yml | 5 +++++ .eslintrc.js | 4 ++-- .prettierrc | 2 +- __tests__/Document.test.js | 8 ++++---- __tests__/_intergration.test.js | 8 ++++---- babel.config.js | 10 +++++----- bin/presentation-merger.js | 2 +- src/Document.js | 34 ++++++++++++++++----------------- src/Presentation.js | 2 +- 9 files changed, 40 insertions(+), 35 deletions(-) create mode 100644 .codeclimate.yml diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 0000000..5a60043 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,5 @@ +plugins: + eslint: + enabled: true + config: + config: ./eslintrc.js \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 786f60c..eb21c4e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -7,8 +7,8 @@ module.exports = { parser: 'babel-eslint', extends: ['eslint:recommended', 'plugin:prettier/recommended'], rules: { - 'semi': ['error', 'always'], - 'prettier/prettier': 'error', + semi: ['error', 'always'], + 'prettier/prettier': ['error', { sindleQuote: true }], 'max-lines-per-function': ['error', 25], 'no-console': [ 'error', diff --git a/.prettierrc b/.prettierrc index f081f7d..70f3a97 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,5 @@ --- -trailingComma: "es5" +trailingComma: "none" tabWidth: 2 semi: true singleQuote: true diff --git a/__tests__/Document.test.js b/__tests__/Document.test.js index 95da4a1..85686ad 100644 --- a/__tests__/Document.test.js +++ b/__tests__/Document.test.js @@ -27,7 +27,7 @@ async function readFixture(filename) { return { presentation, style, - subject, + subject }; } @@ -48,21 +48,21 @@ describe('Document', () => { expect.objectContaining({ mimeType: 'application/vnd.oasis.opendocument.presentation', path: '/', - version: '1.2', + version: '1.2' }) ); expect(subject.manifestFiles).toContainEqual( expect.objectContaining({ mimeType: 'text/xml', - path: 'content.xml', + path: 'content.xml' }) ); expect(subject.manifestFiles).toContainEqual( expect.objectContaining({ mimeType: 'text/xml', - path: 'styles.xml', + path: 'styles.xml' }) ); }); diff --git a/__tests__/_intergration.test.js b/__tests__/_intergration.test.js index d2d7839..e10dc62 100644 --- a/__tests__/_intergration.test.js +++ b/__tests__/_intergration.test.js @@ -23,7 +23,7 @@ describe('Intergration', () => { await mergeFiles( [ path.join(__dirname, '__fixtures__/file1.odp'), - path.join(__dirname, '__fixtures__/file2.odp'), + path.join(__dirname, '__fixtures__/file2.odp') ], filePath ); @@ -33,21 +33,21 @@ describe('Intergration', () => { expect(files).toContainEqual( expect.objectContaining({ path: 'content.xml', - type: 'file', + type: 'file' }) ); expect(files).toContainEqual( expect.objectContaining({ path: 'META-INF/manifest.xml', - type: 'file', + type: 'file' }) ); expect(files).toContainEqual( expect.objectContaining({ path: 'mimetype', - type: 'file', + type: 'file' }) ); diff --git a/babel.config.js b/babel.config.js index f037a1a..6c3be4c 100644 --- a/babel.config.js +++ b/babel.config.js @@ -4,9 +4,9 @@ module.exports = { '@babel/preset-env', { targets: { - node: 'current', - }, - }, - ], - ], + node: 'current' + } + } + ] + ] }; diff --git a/bin/presentation-merger.js b/bin/presentation-merger.js index f50c374..21ddb06 100755 --- a/bin/presentation-merger.js +++ b/bin/presentation-merger.js @@ -30,7 +30,7 @@ program let destination = process.stdout; if (options.file) { destination = fs.createWriteStream(path.resolve(options.file), { - flags: 'w', + flags: 'w' }); } if (allExist) { diff --git a/src/Document.js b/src/Document.js index 92bd64d..a9d484a 100644 --- a/src/Document.js +++ b/src/Document.js @@ -22,12 +22,12 @@ export default class Document extends EventEmitter { this.manifestFiles = this.manifestFilesInitial; this.counter = 0; this.doc = { - 'office:document-content': {}, + 'office:document-content': {} }; this.stylesDoc = { 'office:document-styles': { - 'office:version': '1.2', - }, + 'office:version': '1.2' + } }; } @@ -36,16 +36,16 @@ export default class Document extends EventEmitter { { mimeType: 'application/vnd.oasis.opendocument.presentation', path: '/', - version: '1.2', + version: '1.2' }, { mimeType: 'text/xml', - path: 'content.xml', + path: 'content.xml' }, { mimeType: 'text/xml', - path: 'styles.xml', - }, + path: 'styles.xml' + } ]; } @@ -70,7 +70,7 @@ export default class Document extends EventEmitter { 'office:document-content.office:automatic-styles.style:style', 'office:document-content.office:automatic-styles.text:list-style', 'office:document-content.office:body.office:presentation.draw:page', - 'office:document-content.office:body.office:presentation.presentation:settings', + 'office:document-content.office:body.office:presentation.presentation:settings' ]; } @@ -91,7 +91,7 @@ export default class Document extends EventEmitter { 'office:document-styles.office:automatic-styles.style:style', 'office:document-styles.office:master-styles.draw:layer-set', 'office:document-styles.office:master-styles.style:handout-master', - 'office:document-styles.office:master-styles.style:master-page', + 'office:document-styles.office:master-styles.style:master-page' ]; } @@ -131,8 +131,8 @@ export default class Document extends EventEmitter { streamFiles: true, compression: 'DEFLATE', compressionOptions: { - level: 9, - }, + level: 9 + } }; } @@ -175,14 +175,14 @@ export default class Document extends EventEmitter { 'manifest:manifest': { 'xmlns:manifest': 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0', 'manifest:version': '1.2', - 'manifest:file-entry': [], - }, + 'manifest:file-entry': [] + } }; output['manifest:manifest']['manifest:file-entry'] = this.manifestFiles.map( file => { let out = { 'manifest:full-path': file.path, - 'manifest:media-type': file.mimeType, + 'manifest:media-type': file.mimeType }; if (file.version) { out['manifest:version'] = file.version; @@ -197,7 +197,7 @@ export default class Document extends EventEmitter { return format(toXml(object), { xmlSelfClosingSpace: true, xmlWhitespaceSensitivity: 'ignore', - parser: 'xml', + parser: 'xml' }); } @@ -219,12 +219,12 @@ export default class Document extends EventEmitter { this.files.push(file); this.manifestFiles.push({ mimeType: manifestFile['manifest:media-type'], - path: file.path, + path: file.path }); return { mimeType: manifestFile['manifest:media-type'], pathPrevious: manifestFile['manifest:full-path'], - path: file.path, + path: file.path }; } } diff --git a/src/Presentation.js b/src/Presentation.js index 1a08ef4..e6be420 100644 --- a/src/Presentation.js +++ b/src/Presentation.js @@ -25,7 +25,7 @@ export default class Presentation { _uniqueStyleIDs() { [ 'office:document-content.office:automatic-styles.style:style', - 'office:document-content.office:automatic-styles.text:list-style', + 'office:document-content.office:automatic-styles.text:list-style' ].forEach(key => { this.data = this._renameStyleKeys(this.data, key); }); From 318db70fadeec66071263b6bdb98d26b64e0b9fc Mon Sep 17 00:00:00 2001 From: Kyle Welsby Date: Fri, 6 Mar 2020 13:47:14 +0000 Subject: [PATCH 13/13] =?UTF-8?q?=E2=9C=85=E2=99=BB=EF=B8=8F=20simplify=20?= =?UTF-8?q?duplicate=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __tests__/Document.test.js | 33 +- __tests__/__snapshots__/Document.test.js.snap | 292 +++++++++--------- 2 files changed, 158 insertions(+), 167 deletions(-) diff --git a/__tests__/Document.test.js b/__tests__/Document.test.js index 85686ad..1a7c031 100644 --- a/__tests__/Document.test.js +++ b/__tests__/Document.test.js @@ -137,28 +137,19 @@ describe('Document', () => { expect(subject.stylesDoc).toMatchSnapshot(); }); - describe('master-page', () => { - let actual; - beforeEach(() => { - let key = - 'office:document-styles.office:master-styles.style:master-page'; - actual = get(subject.stylesDoc, key); - }); - - it('contains the expected master pages', () => { - expect(actual).toMatchSnapshot(); - }); - }); - - describe('office:automatic-styles.style:style', () => { - let actual; - beforeEach(() => { - let key = 'office:document-styles.office:automatic-styles.style:style'; - actual = get(subject.stylesDoc, key); - }); + [ + 'office:document-styles.office:master-styles.style:master-page', + 'office:document-styles.office:automatic-styles.style:style' + ].forEach(key => { + describe(key, () => { + let actual; + beforeEach(() => { + actual = get(subject.stylesDoc, key); + }); - it('contains the automatic-styles from both files', () => { - expect(actual).toMatchSnapshot(); + it(`contains the expected contents of ${key}`, () => { + expect(actual).toMatchSnapshot(); + }); }); }); }); diff --git a/__tests__/__snapshots__/Document.test.js.snap b/__tests__/__snapshots__/Document.test.js.snap index 0389e70..90fe575 100644 --- a/__tests__/__snapshots__/Document.test.js.snap +++ b/__tests__/__snapshots__/Document.test.js.snap @@ -2880,151 +2880,6 @@ Object { } `; -exports[`Document mergeStyles master-page contains the expected master pages 1`] = ` -Array [ - Object { - "draw:frame": Array [ - Object { - "draw:image": Object { - "text:p": Object {}, - "xlink:actuate": "onLoad", - "xlink:href": "Pictures/100000000000032000000258E080B12F.jpg", - "xlink:show": "embed", - "xlink:type": "simple", - }, - "draw:layer": "backgroundobjects", - "draw:style-name": "Mgr1", - "draw:text-style-name": "MP1", - "svg:height": "21cm", - "svg:width": "28cm", - "svg:x": "-0.001cm", - "svg:y": "-0.001cm", - }, - Object { - "draw:layer": "backgroundobjects", - "draw:text-box": Object {}, - "presentation:class": "title", - "presentation:placeholder": "true", - "presentation:style-name": "prs-novelty-title", - "svg:height": "3.506cm", - "svg:width": "23.911cm", - "svg:x": "2.058cm", - "svg:y": "1.943cm", - }, - Object { - "draw:layer": "backgroundobjects", - "draw:text-box": Object {}, - "presentation:class": "outline", - "presentation:placeholder": "true", - "presentation:style-name": "prs-novelty-outline1", - "svg:height": "13.23cm", - "svg:width": "23.384cm", - "svg:x": "2.285cm", - "svg:y": "5.938cm", - }, - ], - "draw:style-name": "Mdp1", - "presentation:notes": Object { - "draw:frame": Object { - "draw:layer": "backgroundobjects", - "draw:text-box": Object { - "draw:corner-radius": "3107.312cm", - }, - "presentation:class": "notes", - "presentation:placeholder": "true", - "presentation:style-name": "prs-novelty-notes", - "svg:height": "11.409cm", - "svg:width": "14.517cm", - "svg:x": "3.249cm", - "svg:y": "14.13cm", - }, - "draw:page-thumbnail": Object { - "draw:layer": "backgroundobjects", - "presentation:class": "page", - "presentation:style-name": "prs-novelty-title", - "svg:height": "10.279cm", - "svg:width": "13.705cm", - "svg:x": "3.647cm", - "svg:y": "2.853cm", - }, - "style:page-layout-name": "PM2", - }, - "style:name": "prs-novelty", - "style:page-layout-name": "PM1", - }, - Object { - "draw:frame": Array [ - Object { - "draw:layer": "backgroundobjects", - "draw:text-box": Object { - "draw:corner-radius": "0.065cm", - }, - "presentation:class": "title", - "presentation:placeholder": "true", - "presentation:style-name": "prs-strategy-title", - "svg:height": "3.506cm", - "svg:width": "23.911cm", - "svg:x": "2.058cm", - "svg:y": "0.325cm", - }, - Object { - "draw:layer": "backgroundobjects", - "draw:text-box": Object {}, - "presentation:class": "outline", - "presentation:placeholder": "true", - "presentation:style-name": "prs-strategy-outline1", - "svg:height": "13.23cm", - "svg:width": "23.548cm", - "svg:x": "3.023cm", - "svg:y": "6.178cm", - }, - Object { - "draw:image": Object { - "text:p": Object {}, - "xlink:actuate": "onLoad", - "xlink:href": "Pictures/2000023600002305000012CD3628FC8C.wmf", - "xlink:show": "embed", - "xlink:type": "simple", - }, - "draw:layer": "backgroundobjects", - "draw:style-name": "Mgr1", - "draw:text-style-name": "MP1", - "svg:height": "2.937cm", - "svg:width": "5.47cm", - "svg:x": "22.048cm", - "svg:y": "17.365cm", - }, - ], - "draw:style-name": "Mdp1", - "presentation:notes": Object { - "draw:frame": Object { - "draw:layer": "backgroundobjects", - "draw:text-box": Object {}, - "presentation:class": "notes", - "presentation:placeholder": "true", - "presentation:style-name": "prs-strategy-notes", - "svg:height": "11.409cm", - "svg:width": "14.517cm", - "svg:x": "3.249cm", - "svg:y": "14.13cm", - }, - "draw:page-thumbnail": Object { - "draw:layer": "backgroundobjects", - "presentation:class": "page", - "presentation:style-name": "prs-strategy-title", - "svg:height": "10.279cm", - "svg:width": "13.705cm", - "svg:x": "3.647cm", - "svg:y": "2.853cm", - }, - "style:page-layout-name": "PM2", - }, - "style:name": "prs-strategy", - "style:page-layout-name": "PM1", - }, -] -`; - exports[`Document mergeStyles merges style content from the presentation into the document style 1`] = ` Object { "office:document-styles": Object { @@ -12984,7 +12839,7 @@ Object { } `; -exports[`Document mergeStyles office:automatic-styles.style:style contains the automatic-styles from both files 1`] = ` +exports[`Document mergeStyles office:document-styles.office:automatic-styles.style:style contains the expected contents of office:document-styles.office:automatic-styles.style:style 1`] = ` Array [ Object { "style:drawing-page-properties": Object { @@ -13088,3 +12943,148 @@ Array [ }, ] `; + +exports[`Document mergeStyles office:document-styles.office:master-styles.style:master-page contains the expected contents of office:document-styles.office:master-styles.style:master-page 1`] = ` +Array [ + Object { + "draw:frame": Array [ + Object { + "draw:image": Object { + "text:p": Object {}, + "xlink:actuate": "onLoad", + "xlink:href": "Pictures/100000000000032000000258E080B12F.jpg", + "xlink:show": "embed", + "xlink:type": "simple", + }, + "draw:layer": "backgroundobjects", + "draw:style-name": "Mgr1", + "draw:text-style-name": "MP1", + "svg:height": "21cm", + "svg:width": "28cm", + "svg:x": "-0.001cm", + "svg:y": "-0.001cm", + }, + Object { + "draw:layer": "backgroundobjects", + "draw:text-box": Object {}, + "presentation:class": "title", + "presentation:placeholder": "true", + "presentation:style-name": "prs-novelty-title", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "1.943cm", + }, + Object { + "draw:layer": "backgroundobjects", + "draw:text-box": Object {}, + "presentation:class": "outline", + "presentation:placeholder": "true", + "presentation:style-name": "prs-novelty-outline1", + "svg:height": "13.23cm", + "svg:width": "23.384cm", + "svg:x": "2.285cm", + "svg:y": "5.938cm", + }, + ], + "draw:style-name": "Mdp1", + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "backgroundobjects", + "draw:text-box": Object { + "draw:corner-radius": "3107.312cm", + }, + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "prs-novelty-notes", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "backgroundobjects", + "presentation:class": "page", + "presentation:style-name": "prs-novelty-title", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "style:page-layout-name": "PM2", + }, + "style:name": "prs-novelty", + "style:page-layout-name": "PM1", + }, + Object { + "draw:frame": Array [ + Object { + "draw:layer": "backgroundobjects", + "draw:text-box": Object { + "draw:corner-radius": "0.065cm", + }, + "presentation:class": "title", + "presentation:placeholder": "true", + "presentation:style-name": "prs-strategy-title", + "svg:height": "3.506cm", + "svg:width": "23.911cm", + "svg:x": "2.058cm", + "svg:y": "0.325cm", + }, + Object { + "draw:layer": "backgroundobjects", + "draw:text-box": Object {}, + "presentation:class": "outline", + "presentation:placeholder": "true", + "presentation:style-name": "prs-strategy-outline1", + "svg:height": "13.23cm", + "svg:width": "23.548cm", + "svg:x": "3.023cm", + "svg:y": "6.178cm", + }, + Object { + "draw:image": Object { + "text:p": Object {}, + "xlink:actuate": "onLoad", + "xlink:href": "Pictures/2000023600002305000012CD3628FC8C.wmf", + "xlink:show": "embed", + "xlink:type": "simple", + }, + "draw:layer": "backgroundobjects", + "draw:style-name": "Mgr1", + "draw:text-style-name": "MP1", + "svg:height": "2.937cm", + "svg:width": "5.47cm", + "svg:x": "22.048cm", + "svg:y": "17.365cm", + }, + ], + "draw:style-name": "Mdp1", + "presentation:notes": Object { + "draw:frame": Object { + "draw:layer": "backgroundobjects", + "draw:text-box": Object {}, + "presentation:class": "notes", + "presentation:placeholder": "true", + "presentation:style-name": "prs-strategy-notes", + "svg:height": "11.409cm", + "svg:width": "14.517cm", + "svg:x": "3.249cm", + "svg:y": "14.13cm", + }, + "draw:page-thumbnail": Object { + "draw:layer": "backgroundobjects", + "presentation:class": "page", + "presentation:style-name": "prs-strategy-title", + "svg:height": "10.279cm", + "svg:width": "13.705cm", + "svg:x": "3.647cm", + "svg:y": "2.853cm", + }, + "style:page-layout-name": "PM2", + }, + "style:name": "prs-strategy", + "style:page-layout-name": "PM1", + }, +] +`;